This project is archived and is in readonly mode.

#3687 ✓ invalid
Lyle

nested attributes with belongs_to only supports one use case

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

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

Comments and changes to this ticket

  • Matt Jones

    Matt Jones January 13th, 2010 @ 01:38 AM

    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 by having a select attached to project_id (and/or nifty autocompleter stuff as needed).

  • Lyle

    Lyle January 13th, 2010 @ 11:02 PM

    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.

  • Daniel Heath

    Daniel Heath January 14th, 2010 @ 05:24 AM

    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).

  • Ryan Bigg

    Ryan Bigg June 12th, 2010 @ 03:17 AM

    • State changed from “new” to “open”

    Please submit a patch if the documentation is still confusing.

  • Neeraj Singh

    Neeraj Singh July 29th, 2010 @ 02:21 PM

    • State changed from “open” to “invalid”
    • Importance changed from “” to “Low”

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

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

Tickets have moved to Github

The new ticket tracker is available at https://github.com/rails/rails/issues

Shared Ticket Bins

Pages