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

¿Fue útil?

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

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