Tak, ta walidacja wykonałaby tego rodzaju zapytanie, a takie zapytanie wykona skanowanie tabeli.
Właściwie masz tutaj kilka problemów:
- Weryfikacja podlega warunkom wyścigu, ponieważ logika nie znajduje się w bazie danych, do której należy. Baza danych powinna być odpowiedzialna za wszystkie problemy z integralnością danych, niezależnie od zwykłej ideologii Railsów.
- Twoja walidacja uruchamia skanowanie tabel i nikt nie lubi skanowania tabel.
Możesz rozwiązać oba te problemy za pomocą jednego indeksu. Pierwszy problem rozwiązuje zastosowanie unikalnego indeksu wewnątrz bazy danych. Drugi problem rozwiązuje indeksowanie wyniku lower(username)
zamiast username
.
AFAIK Rails nadal nie rozumie indeksów wyrażeń, więc będziesz musiał zrobić dwie rzeczy:
-
Przełącz z
schema.rb
dostructure.sql
aby Railsy nie zapomniały o twoim indeksie. W plikuconfig/application.rb
będziesz chciał ustawić:config.active_record.schema_format = :sql
Musisz także zacząć używać
db:structure:*
rake zadania zamiastdb:schema:*
zadania. Po przejściu nastructure.sql
, możesz usunąćdb/schema.rb
ponieważ nie będzie już aktualizowany ani używany; będziesz także chciał rozpocząć śledzeniedb/structure.sql
w kontroli wersji. -
Utwórz indeks ręcznie, pisząc trochę kodu SQL w migracji. To proste:
def up connection.execute(%q{ create index idx_users_lower_username on users(lower(username)) }) end def down connection.execute(%q{ drop index idx_users_lower_username }) end
Oczywiście pozostawi ci to rzeczy specyficzne dla PostgreSQL, ale nie ma się czym martwić, ponieważ ActiveRecord i tak nie zapewnia użytecznej przenośności.