[sql] Validar la unicidad de múltiples columnas


Answers

Puede usar validates para validar la uniqueness en una columna:

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

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

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 coherencia. Considere el siguiente ejemplo:

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

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

  3. cada proceso en paralelo valida si hay un registro con los mismos n campos;

  4. la validación de 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 helper para uno (o varios) campos 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 simultáneas intentarán escribir los mismos datos en db, pero en lugar de crear registros duplicados, se generará una excepción ActiveRecord::RecordNotUnique , que deberá manejar por separado:

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

¿Existe 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






Links