Remplacer & # 8220; trouver & # 8221; dans ActiveRecord de manière DRY
-
09-06-2019 - |
Question
J'ai quelques modèles qui nécessitent des conditions de recherche personnalisées. Par exemple, si j’ai un modèle Contact, chaque fois que Contact.find est appelé, je souhaite limiter les contacts renvoyés qui appartiennent uniquement au compte utilisé.
J'ai trouvé ceci via Google (que j'ai un peu personnalisé):
def self.find(*args)
with_scope(:find => { :conditions => "account_id = #{$account.id}" }) do
super(*args)
end
end
Cela fonctionne très bien, sauf dans quelques cas où account_id est ambigu. Je l'ai donc adapté à:
def self.find(*args)
with_scope(:find => { :conditions => "#{self.to_s.downcase.pluralize}.account_id = #{$account.id}" }) do
super(*args)
end
end
Cela fonctionne également très bien, cependant, je veux que ce soit sec. Maintenant, j'ai quelques modèles différents pour lesquels je souhaite utiliser ce type de fonction. Quelle est la meilleure façon de faire cela?
Lorsque vous répondez, veuillez inclure le code pour aider notre esprit à comprendre la métaprogrammation Ruby-fu.
(J'utilise Rails v2.1)
La solution
Vous ne nous dites pas quelle version de rails vous utilisez [edit - c’est sur les rails 2.1, les conseils suivants sont donc pleinement opérationnels], mais je vous recommande d’utiliser le formulaire suivant au lieu de surcharger, trouvez vous-même:
account.contacts.find(...)
Ceci encapsulera automatiquement la recherche dans une étendue où la clause user est incluse (puisque vous avez le account_id, je suppose que vous avez le compte quelque part)
Je vous suggère de consulter les ressources suivantes sur les portées
Autres conseils
Le conseil de Jean est judicieux. En supposant que vos modèles ressemblent à ceci:
class Contact < ActiveRecord::Base
belongs_to :account
end
class Account < ActiveRecord::Base
has_many :contacts
end
Vous devriez utiliser l'association contacts
du compte actuel pour vous assurer que vous n'obtenez que des enregistrements Contact
affectés à ce compte, comme suit:
@account.contacts
Si vous souhaitez ajouter d'autres conditions à votre requête de contacts, vous pouvez les spécifier à l'aide de find:
@account.contacts.find(:conditions => { :activated => true })
Et si vous recherchez constamment des utilisateurs activés, vous pouvez le refactoriser dans une étendue nommée:
class Contact < ActiveRecord::Base
belongs_to :account
named_scope :activated, :conditions => { :activated => true }
end
Ce que vous utiliseriez ensuite comme ceci:
@account.contacts.activated
pour donner une réponse spécifique à votre problème, je suggèrerais de transférer la méthode susmentionnée dans un module à inclure dans les modèles en question; donc vous auriez
class Contact
include NarrowFind
...
end
PS. Méfiez-vous des échappements sql de account_id, vous devez probablement utiliser la syntaxe : conditions = > [" .... =? ", $ account_id]
.