rails/rails — pull request #3991 by akaspick (2011-12-15 05:36:32+00:00)
Title: Allow nested attributes in associations to update values in it's owner o...

This patch allow nested attributes on an association to update the owner object. This worked in Rails 3.0.x, but stopped working in Rails 3.1.

Here's the example between Rails 3.0 and 3.1

```ruby
class Task < AR
accepts_nested_attributes_for :project
end

project = Project.find 1
params[:task] = {:name => 'task', :project_attributes => {:id => '1', :name => 'new name'}}
```

This works in rails 3.0.x (the project name is assigned correctly), but it does not work in rails 3.1.x

```ruby
project.tasks.create params[:task]
puts project.name => 'new name'
```

In rails 3.1.x an exception is raised...
**ActiveRecord::RecordNotFound, "Couldn't find Project with ID=1 for Task with ID="**

The following works in rails 3.1.x even though we're creating the new task from the relation owned by the project object. We still need to pass the project id in explicitly so that it updates correctly.

```ruby
project.tasks.create params[:task].merge(:project_id => project.id)
puts project.name => 'new name'
```

The patch allows the association to work as it did in Rails 3.0.

To fix the issue, the patch does the following...

* Merges in the creation attributes of the owner object so that the new association has reference to the owner.
* Defers assignment of any attributes that contain "sub-attributes" (in hashes) and makes sure that the base values (the first level of attribute keys) are assigned first as this is where the owner foreign key and other references for the new object will be set.
* The deferred nested attributes are then assigned now that the first level of data has been set.

The solution given above for 3.1 can work, but has side affects because of possible hash ordering issues. The :project_id is merged in, but happens to be assigned before the :project_attributes nested attributes are. This of course would fail if Ruby references the :project_attributes attribute before the :project_id and the exception would again be raised.

This patch prevents this issue altogether since the nested attribute assignment is deferred until the base attributes are first set.