2008-09-17 4 views
5

J'ai quelques modèles qui ont besoin d'avoir des conditions de recherche personnalisées placées sur eux. Par exemple, si j'ai un modèle Contact, chaque fois que Contact.find est appelé, je souhaite limiter les contacts renvoyés qui n'appartiennent qu'au compte utilisé.Remplacer "trouver" dans ActiveRecord la manière DRY

J'ai trouvé ce via Google (que j'ai personnalisé un peu):

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

Cela fonctionne très bien, sauf pour les quelques occasions où account_id est ambigu si je l'ai 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 qu'il soit sec. Maintenant, j'ai quelques modèles différents que je veux utiliser ce genre de fonction. Quelle est la meilleure façon de procéder?

Lorsque vous répondez, veuillez inclure le code pour aider nos esprits à saisir la métaprogrammation Ruby-fu.

(j'utilise Rails v2.1)

Répondre

8

Vous ne nous dites pas quelle version de rails que vous utilisez [modifier - il est sur des rails 2.1 ainsi des conseils suivants est pleinement opérationnel], mais je recommand vous utilisez le formulaire ci-dessous au lieu de surcharger vous trouver:

account.contacts.find(...) 

cela enveloppez automatiquement la découverte dans un champ où la clause utilisateur est inclus (puisque vous avez la account_id Je suppose que vous avez le compte quelque part à proximité)

Je vous suggère de vérifier ce qui suit ressources sur les champs

+0

Merci Jean, qui fonctionnera un traitement et est probablement la bonne façon pour le faire. L'introduction du compte est un nouvel ajout au code existant, donc je suppose que j'étais trop compliquer les choses en venant de cette perspective. Je vais juste passer en revue et modifier le code existant pour être étendu par le compte. –

0

pour donner une réponse précise à votre problème, je vous suggère de déplacer la méthode mentionnée ci-dessus dans un module à inclure par les modèles en question; donc vous auriez

class Contact 
    include NarrowFind 
    ... 
end 

PS. attention à l'échappement sql du account_id, vous devriez probablement utiliser la syntaxe :conditions=>[".... =?", $account_id].

+0

Il est très probablement une mauvaise idée de remplacer complètement le chercheur de base d'un modèle car cela briserait les attentes de quiconque à l'extérieur de l'équipe, y compris les plugins (pensez plugin de recherche) sans parler du risque de rupture des rails. – Jean

5

Le conseil de Jean est sain.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 devez utiliser l'association contacts du compte courant pour vous assurer que vous êtes seulement obtenir Contact dossiers scope à ce compte, comme suit:

@account.contacts 

Si vous souhaitez ajouter des conditions supplémentaires à votre recherche de contacts, vous pouvez les spécifier en utilisant find:

@account.contacts.find(:conditions => { :activated => true }) 

Et si vous vous trouvez co l'interrogation nstantly pour les utilisateurs activés, vous pouvez factoriser dans un champ nommé:

class Contact < ActiveRecord::Base 
    belongs_to :account 
    named_scope :activated, :conditions => { :activated => true } 
end 

Que vous utiliserez alors comme ceci:

@account.contacts.activated 
Questions connexes