我使用以下method_missing实现为特定模型提供适应性的named_scope过滤:
class Product < ActiveRecord::Base
def self.method_missing(method_id, *args)
# only respond to methods that begin with 'by_'
if method_id.to_s =~ /^(by\_){1}\w*/i
# extract column name from called method
column = method_id.to_s.split('by_').last
# if a valid column, create a dynamic named_scope
# for it. So basically, I can now run
# >>> Product.by_name('jellybeans')
# >>> Product.by_vendor('Cyberdine')
if self.respond_to?( column.to_sym )
self.send(:named_scope, method_id, lambda {|val|
if val.present?
# (this is simplified, I know about ActiveRecord::Base#find_by_..)
{ :conditions => ["#{base.table_name}.#{column} = ?", val]}
else
{}
end
})
else
super(method_id, args)
end
end
end
end
我知道ActiveRecord :: Base已经使用find_by_<X>
提供了这个,但是我试图超出我给出的示例,并为我的应用程序提供了一些自定义过滤。我想将它提供给选定的模型,而不必将这个片段粘贴到每个模型类中。我想过使用一个模块,然后将它混合在所选择的模型中 - 我对语法有点模糊。
当错误开始堆积时,我已经达到了这一点(我这样做了吗?):
module GenericFilter
def self.extended(base)
base.send(:method_missing, method_id, *args, lambda { |method_id, args|
# ?..
})
end
end
然后我希望能够像这样使用它:
def Product < ActiveRecord::Base
include GenericFilter
end
def Vendor < ActiveRecord::Base
include GenericFilter
end
# etc..
任何帮助都会很棒 - 谢谢。
答案 0 :(得分:2)
实现此目的的两种方法
module GenericModule def self.included(base) base.extend ClassMethods end module ClassMethods def methods_missing #.... end end end class YourModel include GenericModule .. end
或
module GenericModule def method_missing #... end end class MyModel extend GenericModule end
我建议使用第一个,它对我来说似乎更清洁。一般建议,我会避免重写method_missing:)。
希望这有帮助。
答案 1 :(得分:1)
您需要在包含mixin的类的上下文中定义范围。将您的范围包含在include_class.class_eval中,self将正确设置为includes_class。
module Mixin
def self.included(klass)
klass.class_eval do
scope :scope_name, lambda {|*args| ... }
end
end
end
class MyModel
include Mixin
end