unwwwritten
has_many problems with validations
Posted September 11th, 2008 at 9:54 am PDT by S. Brent Faulkner — View Comments
Today's gotcha has to do with using has_many and validations within the child model.
In my use-case I need to create a parent record with one or more children.
The parent is not valid without children and a child is not valid without a parent.
1 class Parent < ActiveRecord::Base 2 has_many :children, :dependent => :destroy 3 validate :must_have_children 4 protected 5 def must_have_children 6 errors.add_to_base('must have at least one child') if children.blank? 7 end 8 end 9 10 class Child < ActiveRecord::Base 11 belongs_to :parent 12 validates_presence_of :parent_id 13 end
So, how do you create them (taking into account the circular validation dependency above)?
1 # create the parent 2 @parent = Parent.new(params[:parent]) 3 # then, add the children 4 if children = params[:children] 5 children.each do |child| 6 # the child params will not include a parent_id (since it does not exist yet) 7 @parent.children.build(child) 8 end 9 end 10 # saving the parent should save the children 11 @parent.save!
Unfortunately, this would result in an error, since the parent of the has_many attempts to validate the children before saving itself. Since the parent has not been saved yet, it has no id. This means that the parent_id is not set in the child, which results in a validation failure.
Fortunately, there is an easy fix workaround...
In your controller code, where you are creating the children... (temporarily) set an explicit parent_id.
1 @parent.children.build(child.merge(:parent_id => 0))
In my case I chose to set it to 0, but as long as it is set, the child will validate. This will allow the parent to be saved, which will assign an id value. That id will then be propagated to the children and BAM! we've created a parent and one or more children with a single save (or save!) call.
blog comments powered by Disqus