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.rbtilstructure.sqlfor at forhindre Rails i at glemme dit indeks. I dinconfig/application.rbdu ønsker at indstille:config.active_record.schema_format = :sqlDu 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.rbda det ikke længere vil blive opdateret eller brugt; du vil også begynde at sporedb/structure.sqli 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.