在ActiveRecord中以DRY方式覆盖"查找"
时间:2020-03-05 18:58:03 来源:igfitidea点击:
我有一些模型需要在其上放置自定义查找条件。例如,如果我有一个Contact模型,则每次调用Contact.find时,我想限制返回的仅属于所使用帐户的联系人。
我是通过Google找到的(我对此做了一些自定义):
def self.find(*args) with_scope(:find => { :conditions => "account_id = #{$account.id}" }) do super(*args) end end
除少数情况下account_id含糊不清之外,这非常有用,因此我将其调整为:
def self.find(*args) with_scope(:find => { :conditions => "#{self.to_s.downcase.pluralize}.account_id = #{$account.id}" }) do super(*args) end end
这也很好用,但是我希望它是干的。现在,我有几种不同的模型希望使用这种功能。做这个的最好方式是什么?
当我们回答时,请包括代码以帮助我们的头脑掌握元编程Ruby-fu。
(我正在使用Rails v2.1)
解决方案
回答
我们没有告诉我们我们正在使用哪个版本的rails [将其编辑在rails 2.1上,因此以下建议是完全可行的],但是我建议我们使用以下形式,而不是使自己过载:
account.contacts.find(...)
这将自动将查找结果包装在包含user子句的范围内(因为我们拥有account_id,所以我假设帐户在某个地方很近)
我建议我们检查以下有关示波器的资源
- http://ryandaigle.com/articles/2008/3/24/what-s-new-in-edge-rails-has-finder-functionality(这不再是边缘了:))
- http://ryandaigle.com/articles/2008/8/20/named-scope-it-s-not-just-for-conditions-ya-know
回答
为了给问题一个具体的答案,我建议将上述方法移到要包含在所讨论的模型中的模块中;所以你有
class Contact include NarrowFind ... end
PS。当心account_id的SQL转义,我们可能应该使用:conditions => [" .... =?",$ account_id]
语法。
回答
尚的建议是正确的。假设模型如下所示:
class Contact < ActiveRecord::Base belongs_to :account end class Account < ActiveRecord::Base has_many :contacts end
我们应该使用当前帐户的"联系人"关联,以确保仅获得该帐户的"联系人"记录,如下所示:
@account.contacts
如果我们想为联系人查询添加更多条件,则可以使用find进行指定:
@account.contacts.find(:conditions => { :activated => true })
而且,如果我们发现自己不断查询激活的用户,则可以将其重构为命名范围:
class Contact < ActiveRecord::Base belongs_to :account named_scope :activated, :conditions => { :activated => true } end
然后我们将使用以下代码:
@account.contacts.activated