valid?
method on your presenter instances to determine if they are valid or not.Step one: You define the validation methods in a module.
module Presenters::ValidationsThen, you
def validates_presence_of(*args)
..
end
def validates_format_of(*args)
..
end
end
extend
the module to add the class methods to your presenter.class AccountInformationPresenterThis implementation also requires that you define
extend Presenters::Validations
validates_presence_of :username, :password
..
valid?
in each presenter class.def valid?When building the second presenter it should be clear that the
self.class.validations.collect do |validation|
unless validation.valid?(self)
self.errors.add(validation.on, validation.message)
end
end.all?
end
end
valid?
should be abstracted. This abstraction could result in another module. The new module could be included thus providing valid?
as an instance method.Step two: Another common approach is to define the class methods in a ClassMethods module inside the Presenters::Validations module.
module Presenters::ValidationsThis approach, while common in Rails, can generate some dislike. A counter argument is that
module ClassMethods
def validates_presence_of(*args)
..
end
def validates_format_of(*args)
..
end
end
def self.included(base)
base.extend(ClassMethods)
end
def valid?
self.class.validations.collect do |validation|
unless validation.valid?(self)
self.errors.add(validation.on, validation.message)
end
end.all?
end
end
include
is designed to add instance methods and using self.included
is clever, but provides unexpected behavior. I've found that people who dislike the self.included
trick prefer to explicitly use both include and extend.class AccountInformationPresenterWhich approach is better?
include Presenter::Validations
extend Presenter::Validations::ClassMethods
..
end
I tend to prefer explicitness; however, if something is used often enough it can turn from an anti-pattern to an idiom. I'm not sure if that is the case or not here, but I think it might be.
I think you mean "extend" instead of "exclude" in the last code block.
ReplyDeleteupdated. thanks.
ReplyDeleteUsing the included callback to extend class methods is a Rails idiom, imo.
ReplyDelete"Using the included callback to extend class methods is a Rails idiom, imo."
ReplyDeleteBeen around longer than rails. in anycase #class_extension the best overall approach (see facets, or google it)
"Then, you extend the module to add the class methods to your presenter." I would say that you're extending the presenter with the module.
ReplyDeletehow is this:
ReplyDeleteclass AccountInformationPresenter
include Presenter::Validations
extend Presenter::Validations::ClassMethods
..
end
different from
class AccountInformationPresenter << Presenter::Validations
or does it result in the same thing without requiring changing the inheritance chain.
Thanks,
Sarah
I'd consider this an idiom now, that is, when I include a module, I fully expect it to go wild on an including class.
ReplyDelete