views:

37

answers:

0

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.