233 votes

La casse de la recherche dans les Rails modèle

Mon modèle de produit contient certains éléments

 Product.first
 => #<Product id: 10, name: "Blue jeans" >

Je suis maintenant à l'importation de certains produits des paramètres à partir d'un autre ensemble de données, mais il y a des incohérences dans l'orthographe des noms. Par exemple, dans l'autre jeu de données, Blue jeans pourrait être orthographié Blue Jeans.

Je voulais Product.find_or_create_by_name("Blue Jeans"), mais cela va créer un nouveau produit, presque identique à la première. Quelles sont mes options si je veux trouver et comparer les lowercase nom.

Les problèmes de Performance n'est pas vraiment important ici: Il y a seulement 100 à 200 produits, et je veux exécuter ce qu'une migration que l'importation des données.

Des idées?

406voto

neutrino Points 11643

Vous aurez probablement à être plus détaillé ici

name = "Blue Jeans"
model = Product.find(:first, :conditions => ["lower(name) = ?", name.downcase]) 
model ||= Product.create(:name => name)

114voto

oma Points 5398

C'est une installation complète dans les Rails, pour ma propre référence. Je suis heureux si elle vous aide aussi.

de la requête:

Product.where("lower(name) = ?", name.downcase).first

le validateur:

validates :name, presence: true, uniqueness: {case_sensitive: false}

l'indice (réponse de la casse index unique dans les Rails/ActiveRecord?):

execute "CREATE UNIQUE INDEX index_products_on_lower_name ON products USING btree (lower(name));"

Je souhaite qu'il y ait une plus belle façon de faire le premier et le dernier, mais là encore, les Rails et les ActiveRecord est open source, nous ne devrions pas nous plaindre - nous pouvons mettre en œuvre nous-mêmes et d'envoyer des pull request.

22voto

Sohan Points 1766

Vous pouvez utiliser les éléments suivants:

validates_uniqueness_of :name, :case_sensitive => false

Veuillez noter que par défaut, le paramètre est :case_sensitive => false, de sorte que vous n'avez même pas besoin d'écrire cette option si vous n'avez pas changé d'autres moyens.

Trouver plus de: http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#method-i-validates_uniqueness_of

14voto

regedarek Points 1578

Dans postgres: user = User.find(:first, :conditions => ['username ~* ?', "regedarek"])

9voto

Mike Woodhouse Points 27748

Citant le SQLite documentation:

Tout autre caractère correspond lui-même ou sa majuscule/minuscule équivalent (c'est à dire insensible à la casse)

...que je ne connaissais pas.Mais il fonctionne:

sqlite> create table products (name string);
sqlite> insert into products values ("Blue jeans");
sqlite> select * from products where name = 'Blue Jeans';
sqlite> select * from products where name like 'Blue Jeans';
Blue jeans

Donc, vous pourriez faire quelque chose comme ceci:

name = 'Blue jeans'
if prod = Product.find(:conditions => ['name LIKE ?', name])
    # update product or whatever
else
    prod = Product.create(:name => name)
end

Pas #find_or_create, je sais, et c'est peut-être pas très de la croix-base de données conviviale, mais vaut la peine de regarder?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X