开发者

Rails 3: Uniqueness validation for nested fields_for

开发者 https://www.devze.com 2023-02-20 22:00 出处:网络
A have two models, \"shop\" and \"product\", linked via has_many :through. In the shop form there are nested attributes for multiple products, and I\'m having a little trouble with the product\'s uni

A have two models, "shop" and "product", linked via has_many :through.

In the shop form there are nested attributes for multiple products, and I'm having a little trouble with the product's uniqueness validation. If I enter a product, save it, then try to enter the same name for a new product, the uniqueness validation triggers successfully.

However, if I enter the same product name in 2 rows of the same nested form, the form is accepted - the uniqueness validation doesn't trigger.

I'm guessing this is a fairly common problem, but I can't find any simple solution. Anyone have any suggestions on the easiest way to ensure uniqueness validations are obeyed within the same nested form?

Edit: Product model included below

class Product < ActiveRecord::Base

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

  validates_presence开发者_如何学运维_of :name
  validates_uniqueness_of :name
end


To expand on Alberto's solution, the following custom validator accepts a field (attribute) to validate, and adds errors to the nested resources.

# 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


You could write a custom validator like

# 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


I found the answer over here :

https://rails.lighthouseapp.com/projects/8994/tickets/2160-nested_attributes-validates_uniqueness_of-fails

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号