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
开发者_如何学Go 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.
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.
精彩评论