Rails 3: проверка уникальности для вложенных полей - PullRequest
10 голосов
/ 30 марта 2011

A имеет две модели, "shop" и "product", связанные через has_many: through.

В форме магазина есть вложенные атрибуты для нескольких продуктов, и у меня возникли небольшие проблемы с проверкой уникальности продукта. Если я ввожу продукт, сохраняю его, затем пытаюсь ввести то же имя для нового продукта, проверка уникальности срабатывает успешно.

Однако, если я введу одно и то же название продукта в 2 рядах одной и той же вложенной формы, форма будет принята - проверка уникальности не сработает.

Полагаю, это довольно распространенная проблема, но я не могу найти простого решения. У кого-нибудь есть предложения по простейшему способу обеспечения проверки уникальности в той же вложенной форме?

Редактировать: Модель продукта включена ниже

class Product < ActiveRecord::Base

  has_many :shop_products
  has_many :shops, :through => :shop_products

  validates_presence_of :name
  validates_uniqueness_of :name
end

Ответы [ 3 ]

17 голосов
/ 08 февраля 2012

Чтобы расширить решение Альберто, следующий пользовательский валидатор принимает поле (атрибут) для проверки и добавляет ошибки во вложенные ресурсы.

# 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
14 голосов
/ 30 марта 2011

Вы можете написать собственный валидатор, например

# 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
0 голосов
/ 12 июня 2012
...