È possibile utilizzare validates
per convalidare uniqueness
su una colonna:
validates :user_id, uniqueness: {scope: :friend_id}
La sintassi per la convalida su più colonne è simile, ma è necessario fornire invece una matrice di campi:
validates :attr, uniqueness: {scope: [:attr1, ... , :attrn]}
Tuttavia , gli approcci di validazione mostrati sopra hanno una condizione di competizione e non possono garantire coerenza. Considera il seguente esempio:
i record della tabella del database dovrebbero essere univoci per n campi;
più ( due o più ) richieste simultanee, gestite da processi separati ciascuna ( server applicazioni, server di background o qualunque cosa tu stia utilizzando ), accedono al database per inserire lo stesso record nella tabella;
ogni processo in parallelo convalida se esiste un record con gli stessi n campi;
la convalida per ogni richiesta viene passata correttamente e ogni processo crea un record nella tabella con gli stessi dati.
Per evitare questo tipo di comportamento, si dovrebbe aggiungere un vincolo univoco alla tabella db. Puoi impostarlo con l' add_index
helper per uno (o più) campi (s) eseguendo la seguente migrazione:
class AddUniqueConstraints < ActiveRecord::Migration
def change
add_index :table_name, [:field1, ... , :fieldn], unique: true
end
end
Avvertenza : anche dopo aver impostato un vincolo univoco, due o più richieste simultanee proveranno a scrivere gli stessi dati su db, ma invece di creare record duplicati, ciò solleverà ActiveRecord::RecordNotUnique
un'eccezione, che dovresti gestire separatamente:
begin
# writing to database
rescue ActiveRecord::RecordNotUnique => e
# handling the case when record already exists
end