Ja, den validering ville gøre den slags forespørgsler, og den slags forespørgsler vil lave en tabelscanning.
Du har faktisk et par problemer her:
- Valideringen er underlagt racebetingelser, fordi logikken ikke er i databasen, hvor den hører hjemme. Databasen bør være ansvarlig for alle dataintegritetsspørgsmål uanset den sædvanlige Rails-ideologi.
- Din validering udløser tabelscanninger, og ingen kan lide tabelscanninger.
Du kan løse begge disse problemer med ét indeks. Det første problem løses ved at bruge et unikt indeks inde i databasen. Det andet problem løses ved at indeksere resultatet af lower(username)
i stedet for username
.
AFAIK Rails forstår stadig ikke indekser på udtryk, så du bliver nødt til at gøre to ting:
-
Skift fra
schema.rb
tilstructure.sql
for at forhindre Rails i at glemme dit indeks. I dinconfig/application.rb
du ønsker at indstille:config.active_record.schema_format = :sql
Du skal også begynde at bruge
db:structure:*
rake-opgaver i stedet fordb:schema:*
opgaver. Når du har skiftet tilstructure.sql
, kan du slettedb/schema.rb
da det ikke længere vil blive opdateret eller brugt; du vil også begynde at sporedb/structure.sql
i revisionskontrol. -
Opret indekset i hånden ved at skrive lidt SQL i en migrering. Dette er nemt:
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
Dette vil selvfølgelig efterlade dig med PostgreSQL-specifikke ting, men det er ikke noget at bekymre sig om, da ActiveRecord alligevel ikke giver dig nogen brugbar portabilitet.