R – How to include an instance method inside a before_save callback in a plugin

activerecordcallbackpluginsrubyruby-on-rails

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_phone_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!

Best Answer

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.

Related Topic