如何在插件中的before_save回调中包含实例方法?

时间:2010-01-29 19:58:00

标签: ruby-on-rails ruby activerecord plugins callback

我正在创建一个插件,并且很难定义一个调用我刚刚定义的实例方法的before_save过滤器。这是一个快速的样本:

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

我想问题是,如何更改实例的上下文而不是类?

我更喜欢调用实例方法,因为类不应该有一个名为'format_phone_fields'的方法,但实例应该。

谢谢!

2 个答案:

答案 0 :(得分:4)

在适当的时候包括您的方法:当您扩展基类时:

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

我没有运行代码,但应该可以运行。我经常做类似的事情。

答案 1 :(得分:2)

当您使用回调宏时,您只能传递要运行的方法的符号,无法传递参数。 rails文档中的'workaround'是使用在正确的上下文中评估的'方法字符串':

before_save 'self.format_phone_fields(....)'

另一种可能性:将您的字段名称存储为类变量并在您的实例中访问该字段,然后您可以使用before_save:format_phone_fields