ActiveRecord の「find」を DRY 方法でオーバーライドする
-
09-06-2019 - |
質問
カスタム検索条件を設定する必要があるモデルがいくつかあります。たとえば、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
これもうまく機能しますが、DRY にしておきたいと思います。現在、この種の機能を使用したいいくつかの異なるモデルがあります。これを行うための最良の方法は何ですか?
回答するときは、メタプログラミング Ruby を理解するのに役立つコードを含めてください。
(Rails v2.1を使用しています)
解決
使用している Rails のバージョンは教えてもらえません [編集 - Rails 2.1 上にあるため、次のアドバイスは完全に機能します] が、 find own をオーバーロードする代わりに次の形式を使用することをお勧めします。
account.contacts.find(...)
これにより、user 句が含まれるスコープで検索が自動的にラップされます (account_id があるので、近い場所にアカウントがあると思われます)
スコープに関する次のリソースを確認することをお勧めします
他のヒント
ジャンのアドバイスは的確だ。モデルが次のようになっていると仮定します。
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
問題に対する具体的な答えを得るには、上記のメソッドをモジュールに移動して、問題のモデルに含めることをお勧めします。そうすればいいでしょう
class Contact
include NarrowFind
...
end
PS.account_id の SQL エスケープに注意してください。おそらく、 :conditions=>[".... =?", $account_id]
構文。