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 with belongs_to only supports one use case

#3687

When using nested attributes with belongs_to, Rails only supports changing the related record rather than which record the object points to. Yes, that's confusing, so consider:

class Task < ActiveRecord::Base
  belongs_to :project
  accepts_nested_attributes_for :project
end

Assume you also have a Task controller and task form with a nested attribute for project name. When you submit the form, the server receives:

"task"=>{"project_attributes"=>{"name"=>"foo", "id"=>"10"} … }

So:
1. Does the user want to change the project's name with id=10 to "foo"?
2. Do they want to change task.project_id to related to an existing project record with name="foo"?
3. Or, do they want to create a new project record with name="foo"?

In Rails 2.3.5, only the first case is supported. Rails executes this SQL statement:

UPDATE projects set name = 'foo' where id = 10

Unfortunately, that renames the project for all tasks. Is this the intended behavior? If so, the documentation should be updated to explicitly state this (currently it doesn't say anything about belongs_to relationships).

Can the other cases be supported? Which would result in something like:

SELECT * from projects where name = 'foo'
INSERT INTO projects (id, name) values (11, 'foo')
UPDATE tasks set project_id = 11 where id = 2

You can see the currently implemented behavior by downloading this example: http://github.com/alloy/complex-form-examples/tree

Reported by Lyle · January 12th, 2010 @ 11:08 PM

State: invalid
Milestone: none
Assigned to: nobody
Importance: Low

Activity

  1. Matt Jones
    Matt Jones

    Not sure if there's a bug here - case 3 in your example can be done by dropping / removing the hidden id field, and I'm not sure what you're looking for in case 2. Normally, you'd handle cases like #2 rake rails:freeze:edge on windows by having a select attached to project_id (and/or nifty autocompleter stuff as needed).

    January 13th, 2010 @ 01:38 AM

  2. Lyle
    Lyle

    I thought nested attributes did more for me than it does. If anything, can the documentation be updated to specifically state what happens when you submit the form? If an ID field is included, that record will be renamed (which affects all records that related to it). If an ID field is not included, a new record is created regardless if one exists already (so you may end up with duplicates).

    I think a better example of this is a task that has one color:

    class Task < ActiveRecord::Base
      belongs_to :color
      accepts_nested_attributes_for :color
    end
    

    In the form, if color is a text_field and the user changes the name from "red" to "green", the Color record with name="red" becomes name="green". If Color includes an RGB attribute then after this update, "green" will have RGB(255,0,0) -- or RGB red.

    If possible, the documentation should include a way to override this behavior -- if that's possible. So, if a developer can include a method in their model, like def color_attributes, to do their own update of the attributes.

    January 13th, 2010 @ 11:02 PM

  3. Daniel Heath
    Daniel Heath

    I don't think this was the intended purpose of accepts_nested_attributes_for.
    The idea is to allow you to edit associated record values or add new associated records.

    If Task belongs_to Project, it only makes sense to use accepts_nested_attributes_for if you want to be able to modify the Project when editing the Task.

    The documentation could be clearer. You should submit a patch (it's not hard to learn how, and contributing can be very rewarding).

    The docs could mention that using an existing primary key value in the attributes hash indicates you are referencing an existing record (and that otherwise a new one will be created).

    January 14th, 2010 @ 05:24 AM

  4. Ryan Bigg
    Ryan Bigg
    • State changed from new to open

    Please submit a patch if the documentation is still confusing.

    June 12th, 2010 @ 03:17 AM

  5. Neeraj Singh
    Neeraj Singh
    • State changed from open to invalid
    • Importance changed from to Low

    Anyone can update documentation at http://github.com/lifo/docrails .

    July 29th, 2010 @ 02:21 PM