I'm creating a plugin and am having a hard time defining a before_save filter that calls an instance method I've just defined. Here's a quick sample:
module ValidatesAndFormatsPhones
def self.included(base)
base.send :extend, ClassMethods
end
module ClassMethods
def validates_and_formats_phones(field_names = [:phone])
send :include, InstanceMethods
# the following variations on calls to :format_p开发者_StackOverflow社区hone_fields fail
before_save send(:format_phone_fields, field_names)
before_save format_phone_fields(field_names)
before_save lambda { send(:format_phone_fields, field_names) }
# EACH OF THE ABOVE RETURNS 'undefined_method :format_phone_fields'
end
end
module InstanceMethods
def format_phone_fields(fields = [:phone], *args)
do stuff...
end
end
end
ActiveRecord::Base.send :include, ValidatesAndFormatsPhones
I guess the question is, how do I change the context to the instance, instead of the class?
I'd prefer to call the instance method because the class shouldn't really have a method called 'format_phone_fields' but the instance should.
Thanks!
Include your method at the right moment: when you're extending the base class:
module ValidatesAndFormatsPhones
def self.included(base)
base.send :extend, ClassMethods
base.send :include, InstanceMethods
end
module ClassMethods
def validates_and_formats_phones(field_names = [:phone])
before_save {|r| r.format_phone_fields(field_names)}
end
end
module InstanceMethods
def format_phone_fields(fields = [:phone], *args)
# do stuff...
end
end
end
ActiveRecord::Base.send :include, ValidatesAndFormatsPhones
I haven't run the code, but it should work. I've done similar things often enough.
as you are using callback macros, you can only pass a symbol for the method you want to run, passing arguments is not possible. the 'workaround' from the rails documentation is to use a 'method string' that gets evaluated in the right context:
before_save 'self.format_phone_fields(....)'
another possibility: store your field names as a class variable and access that one in your instance, then you can use before_save :format_phone_fields
精彩评论