Rails “validates_uniqueness_of” Case Sensitivity

93

Aqui está o modelo (estou usando SQLLite3):

class School < ActiveRecord::Base

  validates_uniqueness_of :name

end

Por exemplo, depois de adicionar "Yale", não posso adicionar "Yale", mas posso adicionar "yale". Como posso tornar a validação sem distinção entre maiúsculas e minúsculas?

EDIT: Found it - Active Record Validations

GeekJock
fonte

Respostas:

232

validates_uniqueness_of :name, :case_sensitive => falsefaz o truque, mas você deve ter em mente que validates_uniqueness_ofisso 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):

  1. O processo A recebe uma solicitação para criar um novo usuário com o nome 'foo'
  2. O processo B faz a mesma coisa
  3. 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.
  4. O processo B faz a mesma coisa e obtém a mesma resposta
  5. O processo A envia a insertdeclaração para o novo registro e é bem-sucedido
  6. Se você tiver uma restrição de banco de dados exigindo exclusividade para esse campo, o Processo B enviará a insertinstruçã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_ofdocumentaçã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.

Jordan Brough
fonte
4
Como observação - aqui está um patch que enviei ao Rails para tentar corrigir esse problema usando restrições de nível de banco de dados: rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/…
Jordan Brough
também, há o problema perene "o usuário clicou duas vezes no botão enviar", mas isso é mais uma solução usando: disable_with
Ghoti
77

No trilho 3, você pode fazer isso em seu modelo:

validates :name, :uniqueness => true

ou sem case_sensitivity

validates :name, :uniqueness => {:case_sensitive => false}
MaximusDominus
fonte
Isso é exatamente o que eu quero.
Jigar Bhatt
1
Tenho feito Rails por mais de 10 anos. Não acredito que estou aprendendo sobre essa opção. Sempre há algo novo para aprender no Rails ... independente do nível de habilidade de cada um.
danielricecodes
24

Existe uma opção onde você pode especificar a distinção entre maiúsculas e minúsculas

  validates_uniqueness_of :name, :case_sensitive => false
vrish88
fonte
1

Há uma pergunta semelhante, mas a resposta é mais interessante: https://stackoverflow.com/a/6422771

Basicamente, o uso de :case_sensitive => falseexecuta uma consulta de banco de dados muito ineficiente.

Victor S
fonte