Topic: accepts_nested_attributes_for validation

I've started to use accepts_nested_attributes_for a nested set using awesome_nested_set. 

My app is in Rails 2.3.8 and I've got a Category which can have one level of sub categories using the one table and awesome_nested_set.

Each Category has a code and name.  I would like the code to be unique depending on the level at which it's at, eg: if it's a main category or sub category.

Here is my model.

class Category < ActiveRecord::Base
  accepts_nested_attributes_for :children, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
  default_scope :order => "lft"

  validates_presence_of :code, :name
  validates_uniqueness_of :code, :scope => :parent_id

This works in most situations.  The problem I have is when I create a Category with a sub category in the one form where the sub category code is equal to a code of a main category.  When looking closely at what happens it seems it's not setting the parent_id before validation.  If I turn off validates_unqueness_of then the system works find but I can of coarse have duplicates on code which is not what I want.

Here is an example of what I'm trying to allow:

id  code  name
1  1       main1
2    1       sub1
3    2       sub2
4  2       main2
5    1       sub1
6  3       main3

So I don't know where it sets the parent_id but I know it does set it on the child somewhere after validate but before create and I would like it to set parent_id before validating the child.

I've tried before_save but I cannot get the parents id.  When using accepts_nested_attributes_of how do I get the main object's id?

What we need to be able to do is:
Validate the parent
Create the parent
Set the parent_id for all children
Validate children
create children

If something goes wrong in any of the validations then all transactions involved are reversed and user is returned to the form with a list of errors.


Detect if it's a child in the validation and compare the code to other children.

Last edited by map7 (2010-10-11 23:38:46)