¿Hay alguna manera de validar que un registro real sea único y no solo una columna? Por ejemplo, un modelo / tabla de amistad no debería poder tener múltiples registros idénticos como:
user_id: 10 | friend_id: 20
user_id: 10 | friend_id: 20
¿Hay alguna manera de validar que un registro real sea único y no solo una columna? Por ejemplo, un modelo / tabla de amistad no debería poder tener múltiples registros idénticos como:
user_id: 10 | friend_id: 20
user_id: 10 | friend_id: 20
Is there a rails-way way
. Y le ofreces un camino sin rieles, pero estándar.The Active Record way claims that intelligence belongs in your models, not in the database.
validates :field_name, unique: true
es propenso a las condiciones de carrera, por lo que, aunque en contra de los rieles, se prefiere una restricción real. @HarryJoy Votaré una respuesta describiendo la forma de restricción.Respuestas:
Puede abarcar una
validates_uniqueness_of
llamada de la siguiente manera.fuente
validates_uniqueness_of [:user_id, :friend_id]
. Tal vez esto necesita ser parcheado?Puede usar
validates
para validaruniqueness
en una columna:La sintaxis para la validación en varias columnas es similar, pero en su lugar debe proporcionar una matriz de campos:
Sin embargo , los enfoques de validación que se muestran arriba tienen una condición de carrera y no pueden garantizar la coherencia. Considere el siguiente ejemplo:
se supone que los registros de la tabla de la base de datos son únicos por n campos;
múltiples ( dos o más ) solicitudes concurrentes, manejadas por procesos separados cada una ( servidores de aplicaciones, servidores de trabajo en segundo plano o lo que sea que esté usando ), accedan a la base de datos para insertar el mismo registro en la tabla;
cada proceso en paralelo valida si hay un registro con los mismos n campos;
la validación para cada solicitud se pasa con éxito y cada proceso crea un registro en la tabla con los mismos datos.
Para evitar este tipo de comportamiento, se debe agregar una restricción única a la tabla db. Puede configurarlo con
add_index
ayuda para uno (o varios) campo (s) ejecutando la siguiente migración:Advertencia : incluso después de haber establecido una restricción única, dos o más solicitudes simultáneas intentarán escribir los mismos datos en db, pero en lugar de crear registros duplicados, esto generará una
ActiveRecord::RecordNotUnique
excepción, que debe manejar por separado:fuente
Esto se puede hacer con una restricción de base de datos en las dos columnas:
add_index :friendships, [:user_id, :friend_id], unique: true
Podría usar un validador de rieles, pero en general recomiendo usar una restricción de base de datos.
Más lectura: https://robots.thoughtbot.com/validation-database-constraint-or-both
fuente