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.rbastructure.sqlper impedire a Rails di dimenticare il tuo indice. Nel tuoconfig/application.rbvorrai impostare:config.active_record.schema_format = :sqlDovrai anche iniziare a usare il
db:structure:*rake task invece didb:schema:*compiti. Dopo essere passato astructure.sql, puoi eliminaredb/schema.rbpoiché non verrà più aggiornato o utilizzato; vorrai anche iniziare a monitoraredb/structure.sqlnel 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.