Conditions avec des variables de liaison et des paramètres facultatifs
-
10-07-2019 - |
Question
Supposons que j'ai un formulaire dans lequel les utilisateurs peuvent rechercher des personnes dont le nom commence par une chaîne nom
particulière, par exemple, "Mi". trouverait & Mike; Mike " et "Miguel". Je créerais probablement une déclaration telle que:
find(:all, :conditions => ['name LIKE ?', "#{name}%"])
Supposons que le formulaire comporte également deux champs facultatifs, hair_color
et eye_color
, qui peuvent être utilisés pour filtrer davantage les résultats. En ignorant la partie nom de la requête, une instruction de recherche pour les personnes pouvant accepter un nombre arbitraire de paramètres facultatifs pourrait ressembler à ceci:
find (: all,: conditions = > {params [: person]})
Ce qui, pour mes deux paramètres facultatifs, se comporterait comme l’équivalent de ceci:
find (: all,: conditions = > {: hair_color = > hair_color,: eye_color = > eye_color})
Ce que je ne comprends pas, c'est comment fusionner ces deux types de requêtes dans lesquelles le champ obligatoire, "nom", est appliqué au "& like" " La condition ci-dessus et les paramètres facultatifs hair_color
et eye_color
(et peut-être d'autres) peuvent être ajoutés pour filtrer davantage les résultats.
Je peux certainement créer une chaîne de requête pour le faire, mais j’estime qu’il doit exister un "chemin de rails". c'est plus élégant. Comment fusionner des paramètres de liaison obligatoires avec des paramètres facultatifs?
La solution
C’est l’utilisation parfaite d’une portée nommée.
créer une portée nommée dans le modèle:
named_scope :with_name_like, lambda {|name|
{:conditions => ['name LIKE ?', "#{name}%"]}
}
À ce stade, vous pouvez appeler
Model.with_name_like("Mi").find(:all, :conditions => params[:person])
Et Rails fusionnera les requêtes pour vous.
Modifier: Code pour Waseem:
Si le nom est facultatif, vous pouvez soit omettre la portée nommée de votre chaîne de méthodes avec une condition if:
unless name.blank?
Model.with_name_like("Mi").find(:all, :conditions => params[:person])
else
Model.find(:all, :conditions => params[:person])
end
Ou vous pouvez redéfinir la portée nommée pour faire la même chose.
named_scope :with_name_like, lambda {|name|
if name.blank?
{}
else
{:conditions => ['name LIKE ?', "#{name}%"]}
end
}
Mettre à jour
Voici la version Rails 3 du dernier extrait de code:
scope :with_name_like, lambda {|name|
if not name.blank?
where('name LIKE ?', "#{name}%")
end
}
Autres conseils
Pour se conformer également à la requête Waseem, en laissant nil vide à la place? (ce qui est utile si vous voulez utiliser "@things = Thing.named_like (params [: name])" directement)
named_scope :named_like, lambda do |*args|
if (name=args.first)
{:conditions => ["name like ?",name]}
else
{}
end
end
# or oneliner version:
named_scope :named_like, lambda{|*args| (name=args.first ? {:conditions => ["name like ?",name]} : {}) } }
J'espère que ça aide