在ActiveRecord中覆盖“查找”DRY方式

时间:2008-09-17 06:02:33

标签: ruby-on-rails ruby activerecord metaprogramming override

我有一些模型需要在其上放置自定义查找条件。例如,如果我有一个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)

3 个答案:

答案 0 :(得分:8)

你没有告诉我们你正在使用哪个版本的rails [编辑 - 它在rails 2.1上,因此以下建议完全可以运行],但是我建议你使用下面的代码而不是重载找到你自己:

account.contacts.find(...) 

这会自动将查找包含在包含user子句的范围内(因为你有account_id我假设你的帐户在某个地方很近)

我建议您检查范围的以下资源

答案 1 :(得分:5)

Jean的建议很合理。假设你的模型看起来像这样:

class Contact < ActiveRecord::Base
  belongs_to :account
end

class Account < ActiveRecord::Base
  has_many :contacts
end

您应该使用当前帐户的contacts关联,以确保您只获取作用于该帐户的Contact条记录,如下所示:

@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

答案 2 :(得分:0)

为你的问题提供一个具体的答案,我建议将上述方法转移到一个模块中,以供有关模型使用;所以你有

class Contact
  include NarrowFind
  ...
end

PS。注意sql转义account_id,你应该使用:conditions=>[".... =?", $account_id]语法。