2010-12-08 31 views
1

J'écris une application rails 3, et j'ai une table de base de données d'utilisateurs. Les utilisateurs ont des colonnes first_name et last_name. Sur ma page qui répertorie les utilisateurs, je souhaite avoir un seul champ de recherche de texte permettant à l'utilisateur de filtrer la liste. Ils doivent être en mesure de taper dans le champ de recherche l'un des suivants: - Un prénom d'un utilisateur - Un nom de famille d'un utilisateur - Un nom complet d'un utilisateur (par exemple "Smith, John")Clause "Where" avec des champs concaténés dans Rails 3

Je ne sais pas comment écrire la clause where qui retournera ces résultats. Le plus proche que j'ai obtenu est ci-dessous, mais la partie des champs concaténés ne fonctionne pas.

where('(first_name LIKE :search) or (last_name LIKE :search) or ("#{last_name}, #{first_name}" LIKE :search)', :search => "%#{search}%") 

Je suis aussi intéressé de savoir s'il y a une meilleure façon de gérer mes ou des déclarations, que cette clause devient tout à fait maladroite.

Merci pour votre aide!

Répondre

2

Dans le cas où cela aiderait quelqu'un d'autre, voici la solution que je suis allé avec:

def self.search(query) 
    if query.blank? 
     scoped 
    else 
     sql = query.split.map do |word| 
     %w[first_name last_name].map do |column| 
     sanitize_sql ["#{column} LIKE ?", "%#{word}%"] 
     end.join(" or ") 
     end.join(") and (") 
     where("(#{sql})") 
    end 
    end 

Merci à Ryan Bates de Railscasts pour cette solution.

+0

Pourriez-vous me dire dans quel Railscasts avez-vous trouvé cette solution? Merci d'avance. –

+0

Ce n'était pas d'un railcast. –

+0

Ok merci! Je l'ai trouvé très utile :) –

2

Vous devez vous rappeler que le where deviendra SQL, et si vous voulez comparer des colonnes concaténées avec une chaîne de recherche, vous devez le faire au niveau base de données/sql.

Maintenant, c'est là que ça devient compliqué, parce que la concaténation en SQL diffère en fonction de votre base de données.

Dans Postgresql et Oracle vous écrire quelque chose comme:

where("(first_name LIKE :search) or (last_name LIKE :search) or (last_name || ',' || first_name LIKE :search)", :search => "%#{search}%" 

Malheureusement, Mysql ne supporte pas l'opérateur de concaténation norme ||, avec MySQL, vous devrez utiliser concat à la place:

where("(first_name LIKE :search) or (last_name LIKE :search) or (concat(last_name, ',', first_name) LIKE :search)", :search => "%#{search}%" 
+1

Existe-t-il une meilleure façon de le faire qu'une clause where? Je préférerais ne rien ajouter de spécifique à une base de données si possible. –

+0

L'autre option est de le faire en mémoire par la suite, mais je déconseille fortement cela. Je pense que l'utilisation de 'where' est la meilleure option: votre base de données est la mieux équipée pour effectuer cette tâche. Dans ces cas, je crains que vous ne pouvez pas éviter d'ajouter du code spécifique à la base de données. – nathanvda