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 models: build should directly assign the parent

#2815

As noted in https://rails.lighthouseapp.com/projects/8994/tickets/1943 sometimes you want to validate the presence of the parent from the child (to handle the case where the child could be independently created for an existing parent)

Example:

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 # as opposed to person_id, if the person is a new_record? w/o id yet end

p = Person.new(:name => "Smith", :children_attributes => [{:name => "John"}] )
p.valid? #=> false (should be true)
p.save #false (should be true)
p.children.first.errors.on(:person_id) #=> "can't be blank"

Reported by sarah (at ultrasaurus) · June 18th, 2009 @ 09:55 PM

State: resolved
Milestone: 2.3.6
Assigned to: Eloy Duran Eloy Duran
Importance: none

Activity

  1. sarah (at ultrasaurus)
    sarah (at ultrasaurus)

    We were thinking that the fix could be something like...

    in nested_attributes.rb, assign_nested_attributes_for_one_to_one_association (around line 250) and like methods to add the reference to the parent:

    assn = send("build_#{association_name}", attributes.except(*UNASSIGNABLE_KEYS)) assn.send("#{parentname}=", self)

    not sure how to get the 'parentname' ...

    June 18th, 2009 @ 10:11 PM

  2. Wolfram Arnold
    Wolfram Arnold
    • Tag changed from nested accepts_nested_attributes_for, validates_presence_of to 2.3.4, accepts_nested_attributes_for, inverse_of, validates_presence_of

    I've just discovered the object identify work by Murray Steele and the new :inverse_of option for associations.

    Using this, the problem described above can be solved, i.e.

    class Person < ActiveRecord::Base

     has_many :children accepts_nested_attributes_for :children, :inverse_of => :person
    

    end

    class Child < ActiveRecord::Base

     belongs_to :person, :inverse_of => :children
     validates_presence_of :person
    

    end

    p = Person.new(:name => "Smith", :children_attributes => [{:name => "John"}] ) p.valid? # ==> true

    I'm attaching a patch that adds test coverage for these cases; it turns out with the latest edge Rails all the pieces are in place for this to work out of the box. :inverse_of contributes this magic. Many thanks to Murray

    June 29th, 2009 @ 10:40 PM

  3. Wolfram Arnold
  4. Wolfram Arnold
    Wolfram Arnold

    For now, the temporary workaround until Rails 2.3.4 is released would be:

    @@@ruby p = Person.new(...) p.save(false) # save without validation if p.valid?

    #...
    

    else

    #...
    

    end

    
    

    June 30th, 2009 @ 03:33 AM

  5. Eloy Duran
    Eloy Duran

    Very nice Wolfram!

    Would you mind moving the last test, which tests nested attributes, to the nested_attributes_test.rb file?

    Thanks

    June 30th, 2009 @ 08:19 AM

  6. Wolfram Arnold
  7. Bodaniel Jeanes
    Bodaniel Jeanes

    damn it ... did this just miss 2.3.3?

    July 12th, 2009 @ 12:30 PM

  8. Eloy Duran
    Eloy Duran

    @Wolfram: Unfortunately I'm unable to see your patch atm. It seems there's an issue with LH. If you could try again or maybe add a pastie/gist, I can verify it on the master branch.

    @Bodaniel: The problem is that the :inverse_of patch hasn't been applied to the 2-3 branch, and won't be in the near future as I understand. So until then, this will stay an issue. Feel free to ask on the mailing list if the :inverse_of patch can be applied on the 2-3 branch, or why it isn't being applied.

    July 12th, 2009 @ 12:53 PM

  9. Wolfram Arnold
  10. Murray Steele
    Murray Steele

    As the author of the :inverse_of patch, I have to say I agree with it not slipping into a 2.3.x release when it didn't make 2.3.0. That said, all is not lost, you could instead use the plugin that I extracted the :inverse_of code from: http://github.com/h-lame/parental_control/.

    July 13th, 2009 @ 09:09 AM

  11. Eloy Duran
    Eloy Duran
    • Milestone cleared.

    @Wolfram: Thanks, I'll verify it against master.

    @Murray: Thanks for chiming in.

    July 13th, 2009 @ 10:09 AM

  12. Wolfram Arnold
    Wolfram Arnold

    @Myrray: Thanks for the pointer to the plugin; that'll solve our problem. I agree with you that given the fundamental nature of the background of :inverse_of with object mapping and identity this is probably not adequate for a dot release.

    July 14th, 2009 @ 09:02 AM

  13. Repository
    Repository

    (from [73f2d37505025a446bb5314a090f412d0fceb8ca]) Add test to verify that the new :inverse_of association option will indeed fix the validation problem for a belongs_to relationship that validates_presence_of the parent, when both the parent and the child are new (in-memory) records. Also check that this works when the parents adds child via nested_attributes_for.

    Lastly, add a require 'models/pet' to association_validation_test.rb, so that test can be run independently (was failing due to that missing dependency). [#2815 status:resolved]

    Signed-off-by: José Valim jose.valim@gmail.com
    http://github.com/rails/rails/commit/73f2d37505025a446bb5314a090f41...

    August 8th, 2009 @ 02:01 PM

  14. Ari Epstein
    Ari Epstein

    The following workaround has been fine for me:

    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
    

    August 18th, 2009 @ 08:23 PM

  15. Sai Emrys
    Sai Emrys

    Bug #3588 is related to this - :autosave => true + accepts_nested_attributes_for = circular validation & blown stack.

    December 16th, 2009 @ 10:02 PM

  16. Eloy Duran
    Eloy Duran
    • Milestone set to 2.3.6

    Hey all, could you please verify that this 2.3.x branch fixes the problems? http://github.com/Fingertips/rails/tree/2-3-stable

    It contains all the :inverse_of patches applied to master, plus a few.

    December 17th, 2009 @ 02:47 PM

  17. Eloy Duran
    Eloy Duran
    • State changed from new to resolved

    The :inverse_of patches have been pushed to 2-3-stable, closing for now.

    December 28th, 2009 @ 08:52 PM

  18. Trevor Turk
    Trevor Turk
    • Importance changed from to

    FYI - I added some info about this in docrails. Please feel free to change/remove this new section, but I think having this documented somewhere is a good idea. It took me a couple of hours to sort out what my problem was and how to fix it today ;)

    http://github.com/lifo/docrails/commit/99c092d4e875856502946c29a1ae...

    August 19th, 2010 @ 08:51 PM

  19. Evgeniy Dolzhenko
    Evgeniy Dolzhenko

    +1 for that being documented. One point though here http://guides.rubyonrails.org/activerecord_validations_callbacks.ht... its said "If you want to be sure that an association is present, you’ll need to test whether the foreign key used to map the association is present, and not the associated object itself." which contradicts your "validates_presence_of :member"

    August 20th, 2010 @ 09:55 AM

  20. Timothy Jones
    Timothy Jones

    This bug is not resolved in the 2.x branch (at least as of 2.3.10).

    November 12th, 2010 @ 05:15 AM