Rails 2.3 - 使用mixin实现动态named_scope
我使用以下 method_missing 实现为某个模型提供可适应的 name_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_
提供了这一点,但我正在尝试做一点除了我给出的示例之外,还提供了一些针对我的应用程序定制的自定义过滤。我希望将其提供给选定的模型,而无需将此代码段粘贴到每个模型类中。我想过使用一个模块,然后将其混合到选择的模型中 - 我只是对语法有点模糊。
当错误开始堆积时,我已经做到了这一点(我这样做对吗?):
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..
任何帮助都会很棒 - 谢谢。
I use the following method_missing implementation to give a certain model an adaptable named_scope filtering:
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
I know this is already provided by ActiveRecord::Base using find_by_<X>
, but I'm trying to go a little bit beyond the example I've given and provide some custom filtering taylored to my application. I'd like to make it available to selected models w/o having to paste this snippet in every model class. I thought of using a module and then mixing it in the models of choice - I'm just a bit vague on the syntax.
I've gotten as far as this when the errors started piling up (am I doing this right?):
module GenericFilter
def self.extended(base)
base.send(:method_missing, method_id, *args, lambda { |method_id, args|
# ?..
})
end
end
Then I hope to be able to use it like so:
def Product < ActiveRecord::Base
include GenericFilter
end
def Vendor < ActiveRecord::Base
include GenericFilter
end
# etc..
Any help will be great - thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
有两种方法可以实现这一目标
,或者
我建议使用第一种方法,它对我来说似乎更干净。作为一般建议,我会避免覆盖 method_missing :)。
希望这有帮助。
Two ways of achieving this
or
I would suggest using the first one, its seems cleaner to me. And as general advise, I'd avoid overriding method_missing :).
Hope this helps.
您需要在包含 mixin 的类的上下文中定义范围。将您的范围包装在include_class.class_eval中,并且self将被正确设置为include_class。
You need to define the scope within the context of the class that is including your mixin. Wrap your scopes in including_class.class_eval and self will be correctly set to the including_class.