Rails "validates_uniqueness_of" Sensibilidad de mayúsculas y minúsculas

95

Aquí está el modelo (estoy usando SQLLite3):

class School < ActiveRecord::Base

  validates_uniqueness_of :name

end

Por ejemplo, después de agregar "Yale", no puedo agregar "Yale" pero puedo agregar "yale". ¿Cómo puedo hacer que la validación no distinga entre mayúsculas y minúsculas?

EDITAR: Lo encontré - Validaciones de registros activos

GeekJock
fuente

Respuestas:

232

validates_uniqueness_of :name, :case_sensitive => falsehace el truco, pero se debe tener en cuenta que validates_uniqueness_ofno no garantizar la unicidad si tiene varios servidores / los procesos del servidor (por ejemplo, correr pasajeros Phusion, múltiples mestizos, etc.) o un servidor multi-roscado. Eso es porque puede obtener esta secuencia de eventos (el orden es importante):

  1. El proceso A recibe una solicitud para crear un nuevo usuario con el nombre 'foo'
  2. El proceso B hace lo mismo
  3. El proceso A valida la unicidad de 'foo' preguntando al DB si ese nombre existe todavía y el DB dice que el nombre aún no existe.
  4. El proceso B hace lo mismo y obtiene la misma respuesta
  5. El proceso A envía la insertdeclaración para el nuevo registro y tiene éxito
  6. Si tiene una restricción de la base de datos que requiere unicidad para ese campo, el proceso B enviará la insertdeclaración para el nuevo registro y fallará con una fea excepción de servidor que regresa del adaptador SQL. Si no tiene una restricción de base de datos, la inserción se realizará correctamente y ahora tiene dos filas con 'foo' como nombre.

Consulte también "Concurrencia e integridad" en la validates_uniqueness_ofdocumentación de Rails.

De Ruby on Rails 3rd Edition :

... a pesar de su nombre, validates_uniqueness_of no garantiza realmente que los valores de columna sean únicos. Todo lo que puede hacer es verificar que ninguna columna tenga el mismo valor que el del registro que se está validando en el momento en que se realiza la validación. Es posible que se creen dos registros al mismo tiempo, cada uno con el mismo valor para una columna que debe ser única, y que ambos registros pasen la validación. La forma más confiable de hacer cumplir la singularidad es con una restricción a nivel de base de datos ".

Consulte también la experiencia de este programador con validates_uniqueness_of.

Una de las formas en que esto sucede comúnmente es el envío doble accidental de una página web al crear una nueva cuenta. Este es difícil de resolver porque lo que el usuario recuperará es el segundo (feo) error y le hará pensar que su registro falló, cuando en realidad fue exitoso. La mejor manera que he encontrado para evitar esto es simplemente usar javascript para tratar de evitar la doble presentación.

Jordan Brough
fuente
4
Como nota, aquí hay un parche que envié a Rails para intentar solucionar este problema utilizando restricciones de nivel de base de datos: rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/…
Jordan Brough
Además, existe el problema perenne de "el usuario hizo doble clic en el botón de envío", pero eso es más una solución usando: disable_with
Ghoti
78

En rails 3 puedes hacer esto en tu modelo:

validates :name, :uniqueness => true

o sin case_sensitivity

validates :name, :uniqueness => {:case_sensitive => false}
MaximusDominus
fuente
Esto es exactamente lo que quiero.
Jigar Bhatt
1
He estado haciendo Rails durante más de 10 años. No puedo creer que esté aprendiendo sobre esta opción. Siempre hay algo nuevo que aprender en Rails ... independientemente del nivel de habilidad de uno.
danielricecodes
25

Hay una opción donde puede especificar la insensibilidad a mayúsculas y minúsculas

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

Hay una pregunta similar pero la respuesta es más interesante: https://stackoverflow.com/a/6422771

Básicamente, el uso :case_sensitive => falserealiza una consulta de base de datos muy ineficiente.

Víctor S
fuente