Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

Nested attributes validations circular dependency

#1943

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" 

Reported by Tamer Salama · February 11th, 2009 @ 04:41 PM

State: wontfix
Milestone: 2.x
Assigned to: nobody
Importance: none

Activity

  1. Eloy Duran
    Eloy Duran
    • Assigned user set to Eloy Duran

    February 17th, 2009 @ 08:35 AM

  2. Eloy Duran
    Eloy Duran
    • 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.

    February 22nd, 2009 @ 04:24 PM

  3. Stephen Touset
    Stephen Touset

    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.

    March 9th, 2009 @ 04:01 PM

  4. Eloy Duran
    Eloy Duran

    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?

    March 9th, 2009 @ 06:32 PM

  5. Michael Kintzer
    Michael Kintzer

    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.

    March 12th, 2009 @ 05:00 AM

  6. Eloy Duran
    Eloy Duran

    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.

    March 12th, 2009 @ 08:39 AM

  7. Chris Bartlett
    Chris Bartlett
    • 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.

    April 22nd, 2009 @ 11:14 PM

  8. Dmitry Polushkin
    Dmitry Polushkin

    What to do? Just use DBMS index :unique => true? Or it's possible to write a patch?

    April 23rd, 2009 @ 07:25 AM

  9. Evgeniy Dolzhenko
    Evgeniy Dolzhenko

    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.

    May 13th, 2009 @ 04:50 PM

  10. Melvin Ram
    Melvin Ram

    So what is the convention to solving this problem? Is there a workaround for the validates_presence_of :parent?

    May 20th, 2009 @ 06:43 AM

  11. sarah (at ultrasaurus)
  12. TMaYaD
    TMaYaD

    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

    May 2nd, 2010 @ 05:54 PM

  13. TMaYaD
    TMaYaD
    • Tag changed from code to nested attributes, code, nested_attributes_for

    May 2nd, 2010 @ 06:07 PM

  14. Sean Corbett
    Sean Corbett
    • 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
    

    July 3rd, 2010 @ 08:24 PM

  15. TMaYaD
    TMaYaD

    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

    February 19th, 2011 @ 08:39 PM