validates_uniqueness_of
d'ActiveRecord est vulnerable to race conditions. Pour vraiment assurer l'unicité nécessite des garanties supplémentaires. Une suggestion du ActiveRecord RDocs est de créer un index unique sur la base de données, par exemple en incluant dans vos migrations:Comment puis-je déterminer si mon objet ActiveRecord enfreint une clé/index de base de données unique?
add_index :recipes, :name, :unique => true
Cela permettra d'assurer au niveau de la base de données que le nom est unique. Mais un inconvénient de cette approche est que l'exception ActiveRecord::StatementInvalid
retournée lors de la tentative d'enregistrement d'une copie n'est pas très utile. On ne peut pas être sûr en attrapant cette exception que l'erreur a été générée par un enregistrement en double et pas seulement par un code SQL cassé. Une solution, comme le suggèrent les RDocs, consiste à analyser le message fourni avec l'exception et à essayer de détecter des mots tels que «duplicate» ou «unique», mais c'est kludgy et le message est spécifique au backend de base de données. Pour SqlLite3, je crois comprendre que le message est totalement générique et ne peut pas être analysé de cette façon. Etant donné qu'il s'agit d'un problème fondamental pour les utilisateurs d'ActiveRecord, il serait bon de savoir s'il existe une approche standard pour gérer ces exceptions. Je vais offrir ma suggestion ci-dessous; veuillez commenter ou fournir des alternatives; Merci!
J'ai implémenté ceci et semble faire le travail. Tenté de retirer validates_uniqueness car cela fait essentiellement la même chose plus efficacement. Publiera toutes les mises à jour pertinentes. – Chinasaur
Un Nitpick très mineur: vous obtenez la mauvaise erreur si le doublon est supprimé entre l'obtention de l'exception et l'interrogation de la copie. – mpartel