Rails 3: Validación de la unicidad para los campos anidados.
-
14-11-2019 - |
Pregunta
A tiene dos modelos, "Tienda" y "producto", vinculado a través de HAD_MANY: A través de.
En el formulario de la tienda, hay atributos anidados para múltiples productos, y estoy teniendo un pequeño problema con la validación de la singularidad del producto.Si ingreso un producto, guárdelo, intente ingresar el mismo nombre para un nuevo producto, la validación de la unicidad desencadena con éxito.
Sin embargo, si ingreso el mismo nombre del producto en 2 filas de la misma forma anidada, se acepta el formulario: la validación de la unicidad no se dispara.
Supongo que este es un problema bastante común, pero no puedo encontrar ninguna solución simple.¿Alguien tiene alguna sugerencia sobre la forma más fácil de garantizar que se obedecen las validaciones de la singularidad dentro de la misma forma anidada ?
Editar: Modelo del producto incluido a continuación
class Product < ActiveRecord::Base
has_many :shop_products
has_many :shops, :through => :shop_products
validates_presence_of :name
validates_uniqueness_of :name
end
Solución
Usted podría escribir un validador personalizado como
# app/validators/products_name_uniqueness_validator.rb
class ProductsNameUniquenessValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
record.errors[attribute] << "Products names must be unique" unless value.map(&:name).uniq.size == value.size
end
end
# app/models/shop.rb
class Shop < ActiveRecord::Base
validates :products, :products_name_uniqueness => true
end
Otros consejos
Para expandir en la solución de Alberto, el siguiente validador personalizado acepta un campo (atributo) para validar, y agrega errores a los recursos anidados.
# config/initializers/nested_attributes_uniqueness_validator.rb
class NestedAttributesUniquenessValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value.map(&options[:field]).uniq.size == value.size
record.errors[attribute] << "must be unique"
duplicates = value - Hash[value.map{|obj| [obj[options[:field]], obj]}].values
duplicates.each { |obj| obj.errors[options[:field]] << "has already been taken" }
end
end
end
# app/models/shop.rb
class Shop < ActiveRecord::Base
validates :products, :nested_attributes_uniqueness => {:field => :name}
end
Encontré la respuesta aquí: