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 are saved twice

#3525

Nested attributes are saved twice. Suppose a definition like this, each having a name column:

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

    class Child < ActiveRecord::Base
        belongs_to :person
        before_save do
            puts "before save"
        end
    end

Creating a person with nested attributes reveils that the child is saved twice (i.e. insert+update, or update+update):

>> Person.create(:name=>'Person',:children_attributes=>[{:name=>'Child'}])
before save!
before save!
=> #<Person id: 1, name: "Person", child_id: nil, created_at: "2009-11-30 21:26:44", updated_at: "2009-11-30 21:26:44">

This usually won't result in two queries though, since the dirty-feature removes all updated columns after the first save:

SQL (0.1ms)   BEGIN
Person Create (0.4ms)   INSERT INTO `people` (`name`, `created_at`, `updated_at`, `child_id`) VALUES('Person', '2009-11-30 21:27:15', '2009-11-30 21:27:15', NULL)
Child Create (0.2ms)   INSERT INTO `children` (`name`, `created_at`, `updated_at`) VALUES('Child', '2009-11-30 21:27:15', '2009-11-30 21:27:15')
SQL (1.3ms)   COMMIT

The reason for this is that AutosaveAssociation#save_collection_association is set up twice as an after-callback for create and update: first when calling has_many :children (AutosaveAssociation overwrites has_many et al and adds a call to add_autosave_association_callbacks), and second when calling accepts_nested_attributes_for (calls add_autosave_association_callbacks right after defining the nested attributes setter). So in turn the save method is overwritten with an equivalent one, and added again as a callback.

I'm not sure what would be the best way to fix this (or whether this is actually intended behavior). The call to add_autosave_association_callbacks should probably be dropped from accepts_nested_attributes_for since it requires an association anyway. Otherwise a simple return if method_defined? save_method at the top of add_autosave_association_callbacks works, but only cures the symptom.

Reported by gix · November 30th, 2009 @ 09:56 PM

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

Activity

  1. Cyrille
    Cyrille

    I confirm the exact same problem on 2.3.5 however the exact same code 2.3.4 works

    December 15th, 2009 @ 05:30 PM

  2. Stephen Heuer
    Stephen Heuer

    I am also seeing this problem in 2.3.5

    December 15th, 2009 @ 09:18 PM

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

    December 30th, 2009 @ 07:37 PM

  4. Eloy Duran
  5. Eloy Duran
    Eloy Duran
    • State changed from new to resolved

    This has recently been fixed on 2-3-stable and master. For instance: http://github.com/rails/rails/commit/146a7505680cbb646c0b9d55dca7cc...

    Thanks!

    January 8th, 2010 @ 11:07 AM

  6. goodwill
    goodwill

    How can I get that applied immediately? I stuck on this already :(

    January 13th, 2010 @ 09:30 AM

  7. Eloy Duran
    Eloy Duran

    @goodwill You'll have to use ‘edge’ rails. If this is a 2.3.x app, you could simply do a checkout of the repo and 2-3-stable branch in ./vendor/rails. If you're on master see this: http://yehudakatz.com/2009/12/31/spinning-up-a-new-rails-app

    Any more questions should go to the rubyonrails-talk mailing list: http://groups.google.com/group/rubyonrails-talk

    January 13th, 2010 @ 09:46 AM