Vous pouvez utiliser validates
de valider uniqueness
sur une colonne :
validates :user_id, uniqueness: {scope: :friend_id}
La syntaxe de la validation sur plusieurs colonnes est similaire, mais vous devez fournir un tableau de champs à la place :
validates :attr, uniqueness: {scope: [:attr1, ... , :attrn]}
Cependant Les approches de validation présentées ci-dessus ont une condition de course et ne peuvent pas garantir la cohérence. Prenons l'exemple suivant :
-
Les enregistrements des tables de la base de données sont censés être uniques par n champs ;
-
multiples ( deux ou plus ) demandes simultanées, traitées par des processus distincts, chacun ( les serveurs d'applications, les serveurs de travail en arrière-plan ou tout ce que vous utilisez. ), accéder à la base de données pour insérer le même enregistrement dans la table ;
-
chaque processus en parallèle valide s'il existe un enregistrement avec le même n champs ;
-
La validation pour chaque demande est passée avec succès, et chaque processus crée un enregistrement dans la table avec les mêmes données.
Pour éviter ce genre de comportement, il faut ajouter un fichier contrainte unique à la table db. Vous pouvez le définir avec add_index
pour un (ou plusieurs) champ(s) en exécutant la migration suivante :
class AddUniqueConstraints < ActiveRecord::Migration
def change
add_index :table_name, [:field1, ... , :fieldn], unique: true
end
end
Caveat : même après avoir défini une contrainte unique, deux ou plusieurs requêtes simultanées essaieront d'écrire les mêmes données dans la base de données, mais au lieu de créer des enregistrements en double, cela entraînera l'apparition d'un message d'erreur. ActiveRecord::RecordNotUnique
exception, que vous devez traiter séparément :
begin
# writing to database
rescue ActiveRecord::RecordNotUnique => e
# handling the case when record already exists
end
2 votes
Essayez d'utiliser "validates_uniqueness_of" dans votre modèle. si cela ne fonctionne pas, essayez de créer un index sur lequel vous pouvez créer une migration de feilds qui inclut une déclaration comme add_index :table, [:column_a, :column_b], :unique => true)
2 votes
Malheureusement
validates :field_name, unique: true
est sujet à des conditions de course, donc même si cela va à l'encontre de la voie ferrée, une contrainte réelle est préférable. @HarryJoy Je vais upvote une réponse décrivant la voie de contrainte.0 votes
Pour être honnête, c'est un excellent moyen de s'assurer que cela n'arrivera JAMAIS. Les validations peuvent être contournées.
2 votes
Une meilleure réponse que toutes celles mentionnées ci-dessous est celle-ci. stackoverflow.com/a/34425284/1612469 car cela apporte une couche supplémentaire pour s'assurer que tout fonctionnera correctement.