Pregunta

¿Existe una forma de rieles de validar que un registro real es ú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
¿Fue útil?

Solución

Puedes alcanzar un validates_uniqueness_of Llame de la siguiente manera.

validates_uniqueness_of :user_id, :scope => :friend_id

Otros consejos

Puedes usar validates validar uniqueness En una columna:

validates :user_id, uniqueness: {scope: :friend_id}

La sintaxis para la validación en varias columnas es similar, pero debe proporcionar una matriz de campos en su lugar:

validates :attr, uniqueness: {scope: [:attr1, ... , :attrn]}

Sin embargo, Los enfoques de validación que se muestran arriba tienen una condición de carrera y no pueden garantizar la consistencia. Considere el siguiente ejemplo:

  1. Se supone que los registros de la tabla de bases de datos son únicos por norte campos;

  2. múltiple (dos o más) solicitudes concurrentes, manejadas por procesos separados cada uno (servidores de aplicaciones, servidores de trabajadores de fondo o lo que sea que esté utilizando), acceder a la base de datos para insertar el mismo registro en la tabla;

  3. Cada proceso en paralelo valida si hay un registro con el mismo norte campos;

  4. La validación para cada solicitud se pasa correctamente, y cada proceso crea un registro en la tabla con los mismos datos.

Para evitar este tipo de comportamiento, uno debe agregar un restricción única a la mesa DB. Puedes configurarlo con add_index Ayudante para un campo (o múltiple) campo ejecutando la siguiente migración:

class AddUniqueConstraints < ActiveRecord::Migration
  def change
   add_index :table_name, [:field1, ... , :fieldn], unique: true
  end
end

Advertencia : Incluso después de establecer una restricción única, dos o más solicitudes concurrentes intentarán escribir los mismos datos en DB, pero en lugar de crear registros duplicados, esto elevará un ActiveRecord::RecordNotUnique excepción, que debe manejar por separado:

begin
# writing to database
rescue ActiveRecord::RecordNotUnique => e
# handling the case when record already exists
end 

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

Puede usar un validador de Rails, pero en general recomiendo usar una restricción de base de datos.

Más lectura: https://robots.thoughtbot.com/validation-database-constraint-or-both

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top