Vous pouvez utiliser validates
pour 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 plutôt fournir un tableau de champs:
validates :attr, uniqueness: {scope: [:attr1, ... , :attrn]}
Cependant , les approches de validation présentées ci-dessus ont une condition de concurrence et ne peuvent pas garantir la cohérence. Prenons l'exemple suivant:
les enregistrements de table de base de données sont censés être uniques par n champs;
plusieurs ( deux ou plus ) demandes simultanées, traitées par des processus séparés chacun ( serveurs d'applications, serveurs de travail en arrière-plan ou tout ce que vous utilisez ), accédez à 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 les mêmes n champs;
la validation de chaque demande est réussie 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 une contrainte unique à la table db. Vous pouvez le définir avec une add_index
assistance 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
Attention : même après avoir défini une contrainte unique, deux requêtes simultanées ou plus essaieront d'écrire les mêmes données dans db, mais au lieu de créer des enregistrements en double, cela déclenchera une ActiveRecord::RecordNotUnique
exception, que vous devrez gérer séparément:
begin
# writing to database
rescue ActiveRecord::RecordNotUnique => e
# handling the case when record already exists
end