accepts_nested_attributes_for validation

nested-forms, ruby-on-rails, validation

Solution

Instead of

validates_uniqueness_of :code, :scope => :parent_id

Try

validates_uniqueness_of :code, :scope => :parent

Besides that you'll need to set in the Category class:

has_many :children, :inverse_of => :category # or whatever name the relation is called in Child

The use of inverse_of will make the children variable `parent` be set before saving, and there is a chance it will work.

Problem

I'm using Rails 2.3.8 and accepts_nested_attributes_for. I have a simple category object which uses awesome_nested_set to allow nested categories. For each category I would like a unique field called code. This would be unique for the category per level. Meaning parent categories will all have unique codes and sub categories will be unique within their own parent category. EG: ``` code name 1 cat1 1 sub cat 1 2 cat2 1 sub cat 1 2 sub cat 2 3 cat3 1 sub1 ``` This works without the validation process but when I try and use something like: validates_uniqueness_of :code, :scope => :parent_id That will not work because the parent has not been saved yet. Here is my model: ``` class Category < ActiveRecord::Base acts_as_nested_set accepts_nested_attributes_for :children, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true default_scope :order => "lft" validates_presence_of :code, :name, :is_child validates_uniqueness_of :code, :scope => :parent_id end ``` I have thought of a different way to do this and it's very close to working, problem is I cannot check for uniqueness between child categories. In this second example I've embedded a hidden field in the form called 'is_child' to flag if the item is a sub category or not. Here is my example of this model: ``` class Category < ActiveRecord::Base acts_as_nested_set accepts_nested_attributes_for :children, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true default_scope :order => "lft" validates_presence_of :code, :name, :is_child #validates_uniqueness_of :code, :scope => :parent_id validate :has_unique_code attr_accessor :is_child private def has_unique_code if self.is_child == "1" # Check here if the code has already been taken this will only work for # updating existing children. else # Check code relating to other parents result = Category.find_by_code(self.code, :conditions => { :parent_id => nil}) if result.nil? true else errors.add("code", "Duplicate found") false end end end end ``` This is very close. If there was a way to detect duplicate codes in the reject_if syntax under accepts_nested_attributes_for then I would be there. This all seems over complicated though and would like suggestions to make it easier. We would like to keep adding categories and sub categories in the one form as it speeds up data entry. Update: Maybe I should be using build or before_save.

Original source