Możesz użyć validates
do sprawdzenia poprawności uniqueness
w jednej kolumnie:
validates :user_id, uniqueness: {scope: :friend_id}
Składnia sprawdzania poprawności w wielu kolumnach jest podobna, ale zamiast tego należy podać tablicę pól:
validates :attr, uniqueness: {scope: [:attr1, ... , :attrn]}
Jednak przedstawione powyżej metody walidacji mają warunek wyścigu i nie mogą zapewnić spójności. Rozważ następujący przykład:
rekordy tabeli bazy danych powinny być unikalne dla n pól;
wiele ( dwóch lub więcej ) równoczesnych żądań, obsługiwanych przez osobne procesy ( serwery aplikacji, serwery procesów roboczych w tle lub cokolwiek używasz ), dostęp do bazy danych w celu wstawienia tego samego rekordu do tabeli;
każdy proces równolegle sprawdza, czy istnieje rekord z tymi samymi n polami;
sprawdzanie poprawności dla każdego żądania zostało pomyślnie zakończone, a każdy proces tworzy rekord w tabeli z tymi samymi danymi.
Aby uniknąć tego rodzaju zachowania, należy dodać unikalne ograniczenie do tabeli db. Możesz ustawić go za pomocą add_index
pomocnika dla jednego (lub wielu) pól, uruchamiając następującą migrację:
class AddUniqueConstraints < ActiveRecord::Migration
def change
add_index :table_name, [:field1, ... , :fieldn], unique: true
end
end
Uwaga : nawet po ustawieniu unikalnego ograniczenia dwa lub więcej współbieżnych żądań spróbuje zapisać te same dane w db, ale zamiast tworzyć duplikaty rekordów, pojawi się ActiveRecord::RecordNotUnique
wyjątek, który należy obsługiwać osobno:
begin
# writing to database
rescue ActiveRecord::RecordNotUnique => e
# handling the case when record already exists
end