Sì, quella convalida farebbe quel tipo di query e quel tipo di query eseguirà una scansione della tabella.
In realtà hai un paio di problemi qui:
- La validazione è soggetta a race condition perché la logica non è nel database a cui appartiene. Il database dovrebbe essere responsabile di tutti i problemi di integrità dei dati indipendentemente dalla consueta ideologia Rails.
- La tua convalida attiva le scansioni delle tabelle e a nessuno piacciono le scansioni delle tabelle.
Puoi risolvere entrambi questi problemi con un indice. Il primo problema viene risolto utilizzando un indice univoco all'interno del database. Il secondo problema viene risolto indicizzando il risultato di lower(username)
anziché username
.
AFAIK Rails continua a non capire gli indici sulle espressioni, quindi dovrai fare due cose:
-
Passa da
schema.rb
astructure.sql
per impedire a Rails di dimenticare il tuo indice. Nel tuoconfig/application.rb
vorrai impostare:config.active_record.schema_format = :sql
Dovrai anche iniziare a usare il
db:structure:*
rake task invece didb:schema:*
compiti. Dopo essere passato astructure.sql
, puoi eliminaredb/schema.rb
poiché non verrà più aggiornato o utilizzato; vorrai anche iniziare a monitoraredb/structure.sql
nel controllo di revisione. -
Crea l'indice a mano scrivendo un po' di SQL in una migrazione. Questo è facile:
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
Ovviamente questo ti lascerà con cose specifiche di PostgreSQL, ma non c'è nulla di cui preoccuparsi poiché ActiveRecord non ti offre comunque alcuna portabilità utile.