Chaining validate method in a plugin, completely stumped

I’m trying to write a plugin which adds some new logic to the validate
method of an ActiveRecord model. However, I still want the user to be
able to define their own validate method in the model, and to call
that as well as my new validate method. What’s happening now is if I
define a validate method and the user defines a validate method as
well, the validate method defined by the user will be called and the
method in my plugin will not be called.

I’ve tried to use alias_method to install my validate method in the
place of the previous validate method, while still allowing me to call
the original method as follows:

alias_method :orig_validate, :validate
alias_method :validate, :new_validate

but when I place this after my validate method definition in my
plugin, I get the following error when starting my server:

undefined method validate' for moduleAttachmentHandler::InstanceMethods’

I need to instruct rails that I’m redefining the validate method from
ActiveRecord::Validations::ClassMethods but I don’t know how to do
this.

My end goal is to be able to add some conditions that a model must
satisfy before being saved, and if it doesn’t pass these conditions,
then I need to add errors to the object. If there’s a better way to
do this than overriding validate, that would also be an option… But
right now, I’m completely stuck and can’t figure this out. Any help
would be greatly appreciated. Thanks,

Mike

Mike G. wrote:

My end goal is to be able to add some conditions that a model must
satisfy before being saved, and if it doesn’t pass these conditions,
then I need to add errors to the object. If there’s a better way to
do this than overriding validate, that would also be an option… But
right now, I’m completely stuck and can’t figure this out. Any help
would be greatly appreciated. Thanks,

How about adding a before_validation or after_validation callback.


We develop, watch us RoR, in numbers too big to ignore.

On 8/24/07, Mark Reginald J. [email protected] wrote:

How about adding a before_validation or after_validation callback.
if I use before_validation, the errors that I add are not carried
through to when the validate method is called. If I return false from
my before_validation method, the error messages added are available,
but the validate method is not called (I guess returning false in
before_validate halts the filter chain). If I use after_validation,
the errors are added to the object, but the object is still allowed to
be saved, even if I return false in after_validation.

So it doesn’t look like I can use the before/after validation
callbacks (and also, are these callbacks chained? ie if I defined my
own before/after validation, and the user defines their own as well,
won’t their definition override mine?)

Thanks,

Mike

Mike G. wrote:

if I use before_validation, the errors that I add are not carried
through to when the validate method is called. If I return false from
my before_validation method, the error messages added are available,
but the validate method is not called (I guess returning false in
before_validate halts the filter chain). If I use after_validation,
the errors are added to the object, but the object is still allowed to
be saved, even if I return false in after_validation.

Yes, you’re right. Neither before_validation nor after_validation
will give you what you want.

So it doesn’t look like I can use the before/after validation
callbacks (and also, are these callbacks chained? ie if I defined my
own before/after validation, and the user defines their own as well,
won’t their definition override mine?)

No, callbacks are properly chained.

You can get your alias_method calls to work if you call them
on the user class after your module has been included, either in
the module “included” method or after the include statement
in your capability-adding method.


We develop, watch us RoR, in numbers too big to ignore.

Mike G. wrote:

is more obtrusive than I wanted. Since this is the ruby/rails world,
I figured there would have to be a better way, but unfortunately I
can’t figure it out.

It’s a bit of a catch-22… I can’t use alias_method in my plugin,
since the plugin is loaded before the entire User class is loaded,
which means that the validate method isn’t available to be aliased…
I wish there was a way of telling rails to alias the method
regardless, under the assumption that the method will be available.
Or to figure out some other way to hook into the validation class.

By putting it in your capability-adding method i meant:

module ActsAsMike
module ClassMethods

end

module InstanceMethods
def new_validate

validate # Call AR::B validate or UserClass validate
end

end
end

class ActiveRecord::Base
def self.acts_as_mike
extend ActsAsMike::ClassMethods
include ActsAsMike::InstanceMethods
alias_method :orig_validate, :validate
alias_method :validate, :new_validate
end
end


We develop, watch us RoR, in numbers too big to ignore.

On 8/24/07, Mark Reginald J. [email protected] wrote:

Mike G. wrote:
You can get your alias_method calls to work if you call them
on the user class after your module has been included, either in
the module “included” method or after the include statement
in your capability-adding method.

yeah, I noticed that works fine, but since this is a plugin, I wanted
to make this as invisible as possible… Requiring the user to add the
alias_method_chain calls after they define their own validate method
is more obtrusive than I wanted. Since this is the ruby/rails world,
I figured there would have to be a better way, but unfortunately I
can’t figure it out.

It’s a bit of a catch-22… I can’t use alias_method in my plugin,
since the plugin is loaded before the entire User class is loaded,
which means that the validate method isn’t available to be aliased…
I wish there was a way of telling rails to alias the method
regardless, under the assumption that the method will be available.
Or to figure out some other way to hook into the validation class.

Thanks for the response Mark,

Mike

On 8/24/07, Mark Reginald J. [email protected] wrote:

 validate # Call AR::B validate or UserClass validate
alias_method :validate, :new_validate

end
end

thanks for the respone Mark, I seem to be getting closer, as I can now
override the default validate method and still call the original
validate method from within new_validate. The only problem is that
the user must place the ‘acts_as_validatable’ class method after
their validate method, otherwise the alias_method call won’t override
their method, and my new_validate method will not be called. Ideally,
I’d like to avoid having the restriction that the user must call
acts_as_validatable after they define their own validate method - is
there any way to get around this?

Here’s the minimal code for the plugin I’ve got right now:

acts_as_validatable.rb
module ActsAsValidatable
module InstanceMethods
def new_validate
logger.warn(“NEW VALIDATE CALLED”)
orig_validate
end
end
end

ActsAsValidatable

class ActiveRecord::Base
def self.acts_as_validatable
include ActsAsValidatable::InstanceMethods

alias_method :orig_validate, :validate
alias_method :validate, :new_validate

end
end

the following works perfectly (the logger shows both “NEW VALIDATE
CALLED” and then “ORIGINAL VALIDATE CALLED”)

my_class.rb
class MyClass < ActiveRecord::Base
def validate
logger.warn(“ORIGINAL VALIDATE CALLED”)
end

acts_as_validatable
end

the following doesn’t work (the only thing that gets logged is
“ORIGINAL VALIDATE CALLED”):

my_class.rb
class MyClass < ActiveRecord::Base
acts_as_validatable

def validate
logger.warn(“ORIGINAL VALIDATE CALLED”)
end
end

Thanks again for the help,

Mike