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?

Était-ce utile?

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top