validates_uniqueness_of :name, :case_sensitive => false
faz o truque, mas você deve ter em mente que validates_uniqueness_of
isso não garante exclusividade se você tiver vários servidores / processos de servidor (por exemplo, executando Phusion Passenger, vários Mongrels, etc) ou um servidor multi-threaded. Isso porque você pode obter esta sequência de eventos (a ordem é importante):
- O processo A recebe uma solicitação para criar um novo usuário com o nome 'foo'
- O processo B faz a mesma coisa
- O processo A valida a exclusividade de 'foo' perguntando ao banco de dados se esse nome ainda existe e o banco de dados diz que o nome ainda não existe.
- O processo B faz a mesma coisa e obtém a mesma resposta
- O processo A envia a
insert
declaração para o novo registro e é bem-sucedido
- Se você tiver uma restrição de banco de dados exigindo exclusividade para esse campo, o Processo B enviará a
insert
instrução para o novo registro e falhará com uma exceção de servidor feia que volta do adaptador SQL. Se você não tiver uma restrição de banco de dados, a inserção será bem-sucedida e agora você tem duas linhas com 'foo' como nome.
Veja também "Concorrência e integridade" na validates_uniqueness_of
documentação do Rails.
Do Ruby on Rails 3ª edição :
... apesar do nome, validates_uniqueness_of não garante realmente que os valores da coluna serão únicos. Tudo o que ele pode fazer é verificar se nenhuma coluna possui o mesmo valor que a do registro que está sendo validado no momento em que a validação é realizada. É possível que dois registros sejam criados ao mesmo tempo, cada um com o mesmo valor para uma coluna que deve ser única, e para que ambos os registros passem na validação. A maneira mais confiável de impor exclusividade é com uma restrição no nível do banco de dados. "
Veja também a experiência deste programador com validates_uniqueness_of
.
Uma maneira pela qual isso normalmente acontece são os envios duplos acidentais de uma página da web ao criar uma nova conta. Isso é difícil de resolver porque o que o usuário receberá de volta é o segundo erro (feio) e isso o fará pensar que seu registro falhou, quando na realidade foi bem-sucedido. A melhor maneira que encontrei de evitar isso é usar javascript para tentar evitar o envio duplo.