ruby-on-rails - ejemplos - ruby on rails que es
Rieles: validar combinación única de 3 columnas (5)
Dependiendo de sus necesidades, también podría agregar una restricción (como parte de la migración de creación de tablas o como una separada) en lugar de la validación del modelo:
add_index :the_table_name, [:brand, :model_name, :fuel_type], :unique => true
Agregar sentido a la restricción única en el nivel de la base de datos tiene sentido, en caso de que las conexiones de bases de datos múltiples estén realizando operaciones de escritura al mismo tiempo.
Hola, quiero validar la combinación única de 3 columnas en mi tabla.
Digamos que tengo una tabla llamada cars con los valores: brand,: model_name y: fuel_type.
Lo que quiero luego es validar si un registro es único basado en la combinación de esos 3. Un ejemplo:
brand model_name fuel_type
Audi A4 Gas
Audi A4 Diesel
Audi A6 Gas
¿Debería todo ser válido? Pero otro registro con ''Audi, A6, Gas'' NO debería ser válido.
Sé de esta validación, pero dudo que realmente haga lo que quiero.
validates_uniqueness_of :brand, :scope => {:model_name, :fuel_type}
El uso de este método de validación junto con ActiveRecord::Validations#save
no garantiza la ausencia de inserciones de registros duplicados, ya que las comprobaciones de exclusividad en el nivel de la aplicación son inherentemente propensas a las condiciones de carrera.
Esto podría incluso suceder si usa transacciones con el nivel de aislamiento ''serializable''. La mejor forma de evitar este problema es agregar un índice único a la tabla de base de datos utilizando ActiveRecord::ConnectionAdapters::SchemaStatements#add_index
. En el caso raro de que se produzca una condición de carrera, la base de datos garantizará la singularidad del campo.
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]
Lo haría de esta manera:
validates_uniqueness_of :model_name, :scope => {:brand_id, :fuel_type_id}
porque tiene más sentido para mí:
- no debe haber "nombres de modelo" duplicados para la combinación de "marca" y "tipo de combustible", frente a
- no debe haber "marcas" duplicadas para la combinación de "nombre del modelo" y "tipo de combustible"
pero es una opinión subjetiva
Por supuesto, si brand y fuel_type son relaciones con otros modelos (si no, simplemente deje caer la parte "_id"). Con la validación de exclusividad no puede verificar las columnas que no son de DB, por lo que debe validar las claves externas en el modelo.
Necesita definir qué atributo está validado, no lo valida todo de una vez; si lo desea, necesita crear una validación por separado para cada atributo, de modo que cuando el usuario se equivoca e intenta crear un registro duplicado, le muestre errores en forma cerca del campo inválido.
Para Rails 4, el código correcto con el nuevo patrón hash
validates :column_name, uniqueness: {scope: [:brand_id, :fuel_type_id]}