sql convertir - Validar la unicidad de múltiples columnas




en filas (5)

¿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

Answers

Probablemente necesites limitaciones reales en la base de datos, porque valida sufre de condiciones de carrera.

validates_uniqueness_of :user_id, :scope => :friend_id

Cuando persiste una instancia de usuario, Rails validará su modelo ejecutando una consulta SELECT para ver si ya existen registros de usuario con el user_id proporcionado. Suponiendo que el registro demuestre ser válido, Rails ejecutará la instrucción INSERT para persistir en el usuario. Esto funciona muy bien si está ejecutando una sola instancia de un único servidor web de procesos / hilos.

En caso de que dos procesos / subprocesos intenten crear un usuario con el mismo ID de usuario al mismo tiempo, puede surgir la siguiente situación.

Con índices únicos en el db en su lugar, la situación anterior se desarrollará de la siguiente manera.

Respuesta tomada de esta publicación de blog - http://robots.thoughtbot.com/the-perils-of-uniqueness-validations



Puede aplicar el alcance de una llamada validates_uniqueness_of siguiente manera.

validates_uniqueness_of :user_id, :scope => :friend_id

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 

Hay un error de sintaxis en su fragmento de código. La validación correcta es:

validates_uniqueness_of :car_model_name, :scope => [:brand_id, :fuel_type_id]

o incluso más corto en ruby ​​1.9.x:

validates_uniqueness_of :car_model_name, scope: [:brand_id, :fuel_type_id]

con rieles 4 puedes usar:

validates :car_model_name, uniqueness: { scope: [:brand_id, :fuel_type_id] }

con rieles 5 puedes usar

validates_uniqueness_of :car_model_name, scope: %i[brand_id fuel_type_id]






sql ruby-on-rails ruby-on-rails-3 activerecord rails-activerecord