Czy istnieje sposób na sprawdzenie, czy rzeczywisty rekord jest unikalny, a nie tylko kolumna? Na przykład model / tabela przyjaźni nie powinna mieć wielu identycznych rekordów, takich jak:
user_id: 10 | friend_id: 20
user_id: 10 | friend_id: 20
Czy istnieje sposób na sprawdzenie, czy rzeczywisty rekord jest unikalny, a nie tylko kolumna? Na przykład model / tabela przyjaźni nie powinna mieć wielu identycznych rekordów, takich jak:
user_id: 10 | friend_id: 20
user_id: 10 | friend_id: 20
Is there a rails-way way
. A ty oferujesz mu drogę bez szyn, ale standard.The Active Record way claims that intelligence belongs in your models, not in the database.
validates :field_name, unique: true
jest podatny na warunki wyścigowe, więc nawet w przypadku torów, preferowane jest rzeczywiste ograniczenie. @HarryJoy Głosuję za odpowiedzią opisującą sposób ograniczenia.Odpowiedzi:
Możesz zawęzić
validates_uniqueness_of
rozmowę w następujący sposób.źródło
validates_uniqueness_of [:user_id, :friend_id]
. Może to trzeba załatać?Możesz użyć
validates
do sprawdzenia poprawnościuniqueness
w jednej kolumnie:Składnia sprawdzania poprawności w wielu kolumnach jest podobna, ale zamiast tego należy podać tablicę pól:
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ę: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:źródło
Można to zrobić za pomocą ograniczenia bazy danych w dwóch kolumnach:
add_index :friendships, [:user_id, :friend_id], unique: true
Możesz użyć walidatora szyn, ale ogólnie polecam użycie ograniczenia bazy danych.
Więcej lektur: https://robots.thoughtbot.com/validation-database-constraint-or-both
źródło