Rails "validates_uniqueness_of" Case Sensitivity

94

Voici le modèle (j'utilise SQLLite3):

class School < ActiveRecord::Base

  validates_uniqueness_of :name

end

Par exemple, après avoir ajouté «Yale», je ne peux pas ajouter «Yale» mais je peux ajouter «yale». Comment puis-je rendre la validation insensible à la casse?

EDIT: Found it - Validations d'enregistrement actives

GeekJock
la source

Réponses:

232

validates_uniqueness_of :name, :case_sensitive => falsefait l'affaire, mais vous devez garder à l'esprit que validates_uniqueness_ofcela ne garantit pas l' unicité si vous avez plusieurs serveurs / processus serveur (par exemple, exécutant Phusion Passenger, plusieurs Mongrels, etc.) ou un serveur multithread. C'est parce que vous pourriez obtenir cette séquence d'événements (l'ordre est important):

  1. Le processus A reçoit une demande de création d'un nouvel utilisateur avec le nom «foo»
  2. Le processus B fait la même chose
  3. Le processus A valide l'unicité de «foo» en demandant à la base de données si ce nom existe encore et la base de données dit que le nom n'existe pas encore.
  4. Le processus B fait la même chose et obtient la même réponse
  5. Le processus A soumet l' insertinstruction pour le nouvel enregistrement et réussit
  6. Si vous avez une contrainte de base de données exigeant l'unicité pour ce champ, le processus B soumettra l' insertinstruction pour le nouvel enregistrement et échouera avec une exception de serveur laide qui revient de l'adaptateur SQL. Si vous n'avez pas de contrainte de base de données, l'insertion réussira et vous avez maintenant deux lignes avec 'foo' comme nom.

Voir aussi "Concurrence et intégrité" dans la validates_uniqueness_ofdocumentation Rails.

De Ruby on Rails 3e édition :

... malgré son nom, validates_uniqueness_of ne garantit pas vraiment que les valeurs de colonne seront uniques. Tout ce qu'il peut faire est de vérifier qu'aucune colonne n'a la même valeur que celle de l'enregistrement en cours de validation au moment de la validation. Il est possible que deux enregistrements soient créés en même temps, chacun avec la même valeur pour une colonne qui doit être unique, et que les deux enregistrements réussissent la validation. Le moyen le plus fiable d'imposer l'unicité est d'utiliser une contrainte au niveau de la base de données. "

Voir aussi l'expérience de ce programmeur avec validates_uniqueness_of.

Cela se produit généralement lors de la double soumission accidentelle d'une page Web lors de la création d'un nouveau compte. C'est une question difficile à résoudre car ce que l'utilisateur récupérera est la deuxième (laide) erreur et cela lui fera penser que son enregistrement a échoué, alors qu'en réalité il a réussi. Le meilleur moyen que j'ai trouvé pour éviter cela est simplement d'utiliser javascript pour essayer d'éviter la double soumission.

Jordan Brough
la source
4
En guise de note - voici un correctif que j'ai soumis à Rails pour essayer de résoudre ce problème en utilisant des contraintes au niveau de la base de données: rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets
Jordan Brough
aussi, il y a le problème éternel "l'utilisateur a double-cliqué sur le bouton d'envoi", mais c'est plus un correctif en utilisant: disable_with
Ghoti
77

Dans les rails 3, vous pouvez le faire dans votre modèle:

validates :name, :uniqueness => true

ou sans case_sensitivity

validates :name, :uniqueness => {:case_sensitive => false}
MaximusDominus
la source
C'est exactement ce que je veux.
Jigar Bhatt
1
Je fais des Rails depuis plus de 10 ans. Je ne peux pas croire que je suis juste en train d'apprendre cette option. Il y a toujours quelque chose de nouveau à apprendre dans Rails ... quel que soit son niveau de compétence.
danielricecodes
25

Il existe une option dans laquelle vous pouvez spécifier l'insensibilité à la casse

  validates_uniqueness_of :name, :case_sensitive => false
vrish88
la source
1

Il y a une question similaire mais la réponse est plus intéressante: https://stackoverflow.com/a/6422771

Fondamentalement, l'utilisation :case_sensitive => falseexécute une requête de base de données très inefficace.

Victor S
la source