This project is archived and is in readonly mode.

#4254 ✓invalid
Tyler Gannon

Assigning nested attributes fails for new object when ID is specified

Reported by Tyler Gannon | March 22nd, 2010 @ 10:13 PM

I see Alloy's name a lot in the recent history for nested_attributes.rb so he might be the best to implement this fix.

Steps to recreate:

for example:

class Person < ActiveRecord::Base
has_many :arms accepts_nested_attributes_for :arms end

now in the console:

Arm.create(:length => "3in") Person.new( { "arms_attributes" => {"0" => { "id" => Arm.last.id.to_s } } } )

Expected:
new Person object with the recently created Arm object added to the arms collection.

Actual:
ActiveRecord::RecordNotFound: Couldn't find Arm with ID=1 for Person with ID=

from /usr/lib/ruby/gems/1.8/gems/activerecord-3.0.0.beta/lib/active_record/nested_attributes.rb:395:in `raise_nested_attributes_record_not_found'
from /usr/lib/ruby/gems/1.8/gems/activerecord-3.0.0.beta/lib/active_record/nested_attributes.rb:357:in `assign_nested_attributes_for_collection_association'
from /usr/lib/ruby/gems/1.8/gems/activerecord-3.0.0.beta/lib/active_record/nested_attributes.rb:347:in `each'
from /usr/lib/ruby/gems/1.8/gems/activerecord-3.0.0.beta/lib/active_record/nested_attributes.rb:347:in `assign_nested_attributes_for_collection_association'
from /usr/lib/ruby/gems/1.8/gems/activerecord-3.0.0.beta/lib/active_record/nested_attributes.rb:252:in `arms_attributes='
from /usr/lib/ruby/gems/1.8/gems/activerecord-3.0.0.beta/lib/active_record/base.rb:1988:in `send'
from /usr/lib/ruby/gems/1.8/gems/activerecord-3.0.0.beta/lib/active_record/base.rb:1988:in `attributes='
from /usr/lib/ruby/gems/1.8/gems/activerecord-3.0.0.beta/lib/active_record/base.rb:1984:in `each'
from /usr/lib/ruby/gems/1.8/gems/activerecord-3.0.0.beta/lib/active_record/base.rb:1984:in `attributes='
from (irb):12

Take a look at that area in nested_attributes.rb:354 and it is expecting that the nested attribute collection should already contain a member with the same id as the one being added, otherwise it will raise an exception. This implies an assumption that if the child object is going to be mentioned in the attributes hash, then it should either be a new object or it should already belong to the parent. This creates a problem for anyone trying to build a new parent object using the ids of the child objects.

Or am I missing something important in the usage here?

Comments and changes to this ticket

  • David Trasbo

    David Trasbo April 15th, 2010 @ 11:51 AM

    • Assigned user set to “Ryan Bigg”

    Tyler,

    In this case you should use arm_ids:

    Person.new(:arm_ids => [1, 2, 3])
    

    This ticket can be marked as invalid.

  • Ryan Bigg

    Ryan Bigg April 15th, 2010 @ 11:52 AM

    • State changed from “new” to “invalid”
  • Dave Myron

    Dave Myron January 10th, 2011 @ 01:03 AM

    • Importance changed from “” to “Low”

    I'd like to reopen discussion on this. Consider a three-level nested attribute setup: Something like Subscription -> User -> Credit Card (each accepting nested attributes of the parent) and in the Subscription form you have the Subscription, User and Credit Card fields.

    If the User exists but doesn't have a Credit Card yet, then this error is thrown when trying to create a Subscription with an existing user and trying to provide Credit Card details. Imagine the Subscription form having a dropdown of existing users which would set subscription[user_attributes][id] and then specifying subscription[user_attributes][credit_card_attributes] values.

    The resulting params would look something like {:subscription => {:user_attributes => {:id => 1, :credit_card_attributes => { ... }}}

    I'd expect that work (as did the original reporter).

    Can you suggest an existing way to accomplish this? (You wouldn't be able to use nested attributes, I'm guessing, and instead have to look for a separate credit_card param and shim it in.)

  • Dave Myron

    Dave Myron January 10th, 2011 @ 07:33 AM

    In assign_nested_attributes_for_one_to_one_association maybe it ought to look at the persisted? state and, if not persisted, reflect on the association and use the its find with the id given in the attributes.

    I'm curious if CVE-2010-3933 (Rails v3.0.1) is related to this.

  • Dave Myron

    Dave Myron January 10th, 2011 @ 07:37 AM

    Hmm... looks like my suggestion above is exactly what was removed in Rails v3.0.1 because of CVE-2010-3933. That's a bummer.

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

Pages