Railsy „validates_uniqueness_of” Rozróżnianie wielkości liter

96

Oto model (używam SQLLite3):

class School < ActiveRecord::Base

  validates_uniqueness_of :name

end

Na przykład po dodaniu „Yale” nie mogę dodać „Yale”, ale mogę dodać „yale”. Jak mogę sprawić, by wielkość liter w walidacji była niewrażliwa?

EDYCJA: Znaleziono - Walidacje rekordów aktywnych

GeekJock
źródło

Odpowiedzi:

232

validates_uniqueness_of :name, :case_sensitive => falsezałatwia sprawę, ale należy pamiętać, że validates_uniqueness_ofnie nie gwarantują wyjątkowość jeśli masz wiele serwerów / procesów serwera (np uruchomiony phusion passenger wielokrotne kundli, etc) lub serwerze wielowątkowe. To dlatego, że możesz otrzymać taką sekwencję zdarzeń (kolejność jest ważna):

  1. Proces A otrzymuje żądanie utworzenia nowego użytkownika o nazwie „foo”
  2. Proces B robi to samo
  3. Proces A sprawdza unikalność „foo”, pytając DB, czy ta nazwa już istnieje, a DB mówi, że nazwa jeszcze nie istnieje.
  4. Proces B robi to samo i otrzymuje taką samą odpowiedź
  5. Proces A przesyła insertoświadczenie dla nowego rekordu i kończy się pomyślnie
  6. Jeśli masz ograniczenie bazy danych wymagające unikalności dla tego pola, proces B prześle insertinstrukcję dla nowego rekordu i zakończy się niepowodzeniem z brzydkim wyjątkiem serwera, który wraca z adaptera SQL. Jeśli nie masz ograniczenia dotyczącego bazy danych, wstawianie się powiedzie i masz teraz dwa wiersze z „foo” jako nazwą.

Zobacz także „Współbieżność i integralność” w validates_uniqueness_ofdokumentacji Railsów.

Z Ruby on Rails 3rd Edition :

... pomimo swojej nazwy validates_uniqueness_of nie gwarantuje, że wartości kolumn będą unikalne. Wszystko, co może zrobić, to sprawdzić, czy żadna kolumna nie ma takiej samej wartości, jak ta w walidowanym rekordzie w momencie przeprowadzania walidacji. Możliwe jest jednoczesne utworzenie dwóch rekordów, z których każdy ma tę samą wartość dla kolumny, która powinna być unikalna, oraz aby oba rekordy przeszły walidację. Najbardziej niezawodnym sposobem wymuszenia unikalności jest ograniczenie na poziomie bazy danych ”.

Zobacz także doświadczenie tego programisty z validates_uniqueness_of.

Jednym ze sposobów, w jakie to się często zdarza, są przypadkowe podwójne zgłoszenia ze strony internetowej podczas tworzenia nowego konta. Jest to trudne do rozwiązania, ponieważ użytkownik odzyska drugi (brzydki) błąd i sprawi, że pomyśli, że ich rejestracja się nie powiodła, podczas gdy w rzeczywistości się udało. Najlepszym sposobem, aby temu zapobiec, jest użycie javascript, aby zapobiec podwójnemu przesyłaniu.

Jordan Brough
źródło
4
Uwaga - oto łatka, którą przesłałem do Railsów, aby spróbować rozwiązać ten problem, wykorzystując ograniczenia na poziomie db: rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/ ...
Jordan Brough
istnieje również odwieczny problem „użytkownik dwukrotnie kliknął przycisk przesyłania”, ale jest to bardziej rozwiązanie za pomocą:
disable_with
78

W szynach 3 możesz to zrobić w swoim modelu:

validates :name, :uniqueness => true

lub bez wrażliwości na wielkość liter

validates :name, :uniqueness => {:case_sensitive => false}
MaximusDominus
źródło
Właśnie tego chcę.
Jigar Bhatt
2
Rails robię od ponad 10 lat. Nie mogę uwierzyć, że dopiero uczę się o tej opcji. W Railsach zawsze jest coś nowego do nauczenia ... niezależnie od poziomu umiejętności.
danielricecodes
25

Istnieje opcja, w której można określić niewrażliwość na wielkość liter

  validates_uniqueness_of :name, :case_sensitive => false
vrish88
źródło
2

Jest podobne pytanie, ale odpowiedź jest bardziej interesująca: https://stackoverflow.com/a/6422771

Zasadniczo użycie :case_sensitive => falsepowoduje wykonanie bardzo nieefektywnego zapytania do bazy danych.

Victor S.
źródło