在ActiveRecord中覆盖"查找"DRY方式

Dan*_*per 5 ruby activerecord overriding metaprogramming ruby-on-rails

我有一些模型需要在其上放置自定义查找条件.例如,如果我有一个Contact模型,每次调用Contact.find时,我想限制返回的仅属于正在使用的Account的联系人.

我通过谷歌找到了这个(我已经定制了一点):

def self.find(*args)
  with_scope(:find => { :conditions =>  "account_id = #{$account.id}" }) do
    super(*args)
  end
end
Run Code Online (Sandbox Code Playgroud)

这很有效,除了少数几个account_id不明确的情况,所以我把它改编成:

def self.find(*args)
  with_scope(:find => { :conditions =>  "#{self.to_s.downcase.pluralize}.account_id = #{$account.id}" }) do
    super(*args)
  end
end
Run Code Online (Sandbox Code Playgroud)

这也很好,但是,我希望它是干的.现在我有一些不同的模型,我希望使用这种功能.做这个的最好方式是什么?

当你回答时,请包含代码,以帮助我们的思想掌握元编程Ruby-fu.

(我正在使用Rails v2.1)

Jea*_*ean 8

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

account.contacts.find(...) 
Run Code Online (Sandbox Code Playgroud)

这将自动将查找包含在包含user子句的作用域中(因为你有account_id我假设你的帐户在某个地方很近)

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


Nat*_*ies 5

让的建议很合理.假设您的模型看起来像这样:

class Contact < ActiveRecord::Base
  belongs_to :account
end

class Account < ActiveRecord::Base
  has_many :contacts
end
Run Code Online (Sandbox Code Playgroud)

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

@account.contacts
Run Code Online (Sandbox Code Playgroud)

如果您想为联系人查询添加更多条件,可以使用find指定它们:

@account.contacts.find(:conditions => { :activated => true })
Run Code Online (Sandbox Code Playgroud)

如果您发现自己不断查询激活的用户,可以将其重构为命名范围:

class Contact < ActiveRecord::Base
  belongs_to :account
  named_scope :activated, :conditions => { :activated => true }
end
Run Code Online (Sandbox Code Playgroud)

然后你将使用这样:

@account.contacts.activated
Run Code Online (Sandbox Code Playgroud)