This project is archived and is in readonly mode.
Nested attributes validations circular dependency
Reported by Tamer Salama | February 11th, 2009 @ 04:41 PM | in 2.x
When using accepts_nested_attributes_for
, a child
object with a validates_presence_of :parent_id
will
not pass the validations upon saving the parent object.
(the child validation is done before the parent id is propagated to the child).
class Person < ActiveRecord::Base
has_many :children
accepts_nested_attributes_for :children
end
class Child < ActiveRecord::Base
belongs_to :person
#Validating that a child has a parent
validates_presence_of :person_id
end
p = Person.new(:name => "Smith", :children_attributes => {"new_1" => {:name => "John"}})
p.valid? #=> false
p.save #false
p.children.first.errors.on(:person_id) #=> "can't be blank"
Comments and changes to this ticket
-
Eloy Duran February 17th, 2009 @ 08:35 AM
- Assigned user set to Eloy Duran
-
Eloy Duran February 22nd, 2009 @ 04:24 PM
- State changed from new to wontfix
I wonder how we could actually handle this. It would mean you'd have to save the parent before the children in order to be able to validate the children. So simply calling parent.valid? would save it and then run the validations on the children. That all seems very complicated to me.
Also, this should already be tested in the framework and not something the developer should need to worry about. However, if you feel there are tests for scenarios missing let me know.
If you still feel a strong need to validate that after creation the foreign key is set, I would suggest adding an after_save callback which verifies this and if not rolls back the transaction.
-
Stephen Touset March 9th, 2009 @ 04:01 PM
This could be resolved by validates_presence_of :parent, rather than validates_presence_of :parent_id. Unfortunately, Rails doesn't set the parent on building the association. Could that be changed?
Either that, or making validates_associated not be completely useless, and do what is implied by its name.
-
Eloy Duran March 9th, 2009 @ 06:32 PM
This could be resolved by validates_presence_of :parent, rather than validates_presence_of :parent_id. Unfortunately, Rails doesn't set the parent on building the association. Could that be changed?
Hmm, having #build directly assign the parent sounds like a good idea in general. Maybe open a separate ticket for it or ask on the ML if there are any known issues with this?
Either that, or making validates_associated not be completely useless, and do what is implied by its name.
Why is validates_associated completely useless?
-
Michael Kintzer March 12th, 2009 @ 05:00 AM
Is there any update regarding the previous suggestion? (Having #build_child directly assign the parent to satisfy a 'validates_presence_of :parent without the need for the parent to already be saved?)
I looked around on the mailing lists and did not see a ticket on this. It seems like a promising approach, and it would allow for a resolution to this issue.
Based on the blog feedback, it seems more than a handful of people do use validates_presence_of :parent_id in their belongs_to relationship models (I recall it being recommended in Dan Chak's excellent Enterprise Rails book) and it seems a shame to ask them to remove or recode that with an after_save callback just so this new feature can work.
-
Eloy Duran March 12th, 2009 @ 08:39 AM
Is there any update regarding the previous suggestion? (Having #build_child directly assign the parent to satisfy a 'validates_presence_of :parent without the need for the parent to already be saved?) I looked around on the mailing lists and did not see a ticket on this. It seems like a promising approach, and it would allow for a resolution to this issue.
Nope, not that I know of. As I already suggested, open up a new ticket which requests this, or better yet, attach a patch.
Based on the blog feedback, it seems more than a handful of people do use validates_presence_of :parent_id in their belongs_to relationship models (I recall it being recommended in Dan Chak's excellent Enterprise Rails book) and it seems a shame to ask them to remove or recode that with an after_save callback just so this new feature can work.
This has nothing to do with any new feature, it just doesn't work this way.
-
Chris Bartlett April 22nd, 2009 @ 11:14 PM
- Tag set to code
There might also be uniqueness conditions that you want to enforce, but these fail as per the discussion above. For example, if you were trying to save a course and enrolments and had a uniqueness condition on enrolments to prevent a student from enrolling in a course more than once:
validates_uniqueness_of :student_id, :scope => :course_id
This validation does not work when creating a new course (say, the user has accidentally added the same student twice on the course form they are submitting). This is an old issue - see: http://dev.rubyonrails.org/ticke...Basically, it means that accepts_nested_attributes_for is not as nice and tidy as one would perhaps expect. Validations need to be handled by the DBMS.
-
Dmitry Polushkin April 23rd, 2009 @ 07:25 AM
What to do? Just use DBMS index :unique => true? Or it's possible to write a patch?
-
Evgeniy Dolzhenko May 13th, 2009 @ 04:50 PM
So it's not in any way related to nested attributes, right?
I was bitten by the same problem ( described here http://railsforum.com/viewtopic.php?pid=96990 ), and still don't get how to build, in the terms of the above example, the Person object with Child object in children association in memory, and then save them with one call.
I.e. get the transaction safety and easier error reporting for building complex objects.
-
Melvin Ram May 20th, 2009 @ 06:43 AM
So what is the convention to solving this problem? Is there a workaround for the validates_presence_of :parent?
-
sarah (at ultrasaurus) June 18th, 2009 @ 09:56 PM
Alright, I wrote up a bug on the suggested approach above: https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets...
-
TMaYaD May 2nd, 2010 @ 05:54 PM
I think we still need to fix it.
In case of a nested resource with its own form, we might want to validate that the child does indeed belong to a parent even if its form is not nested in the parent.
At the very least we need to be able to provide a way to tell weather we are in the model from a nested form or individual form, so that we can validate accordingly.
the workaround I currently use in my apps is to assign an attribute ':nest' ( = self, ie, the parent )to each child before validation on parent and check for it in child -
TMaYaD May 2nd, 2010 @ 06:07 PM
- Tag changed from code to nested attributes, code, nested_attributes_for
-
Sean Corbett July 3rd, 2010 @ 08:24 PM
- Assigned user cleared.
- Importance changed from to
I like Ari Epstine's workaround for this on the related ticket: https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets...
class Person < ActiveRecord::Base has_many :children accepts_nested_attributes_for :children before_validation_on_create :initialize_children def initialize_children children.each { |c| c.parent = self } end end class Child < ActiveRecord::Base belongs_to :person end
-
TMaYaD February 19th, 2011 @ 08:39 PM
A variant to Ari Epstine's work around is using before_add callback
class Person < ActiveRecord::Base
has_many :children, :before_add => :set_nest accepts_nested_attributes_for :children private
def set_nest(child)child.person ||= self
end end
class Child < ActiveRecord::Base
belongs_to :person#Validating that a child has a parent validates_presence_of :person_id, :unless => Proc.new { |c| c.parent && c.parent.new_record? } end
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>
People watching this ticket
Referenced by
- 2578 accepts_nested_attributes_for causes stack level too deep Aha: In my situation, the child model wants to validate_p...
- 1202 Add attributes writer method for an association. @orangechicken See this ticket #1943.
- 2815 nested models: build should directly assign the parent As noted in https://rails.lighthouseapp.com/projects/8994...