开发者

Save changes to a has_many association ONLY when you successfully save the parent object?

Suppose each Project has_many Tasks.

If I do

some_project.tasks = list_of_tasks
some_project.save

The project's tasks get updated even if the save fails. If list_of_tasks开发者_高级运维 consists of new records, the project's tasks get deleted even if the save fails! WHOA!

If the save fails, the project should have the same tasks it had before I started messing with it. How do I get this behavior and why isn't it the default?


Enclose the statements in a transaction:

Project.transaction do
  p.tasks = task_list
  p.save!
end

The save! method throws an exception upon error, which rolls back any changes done to task list.

You can read the documentation if you want to dive a bit more deeply on the subject.


I believe that accepts_nested_attributes_for() will provide the behavior you want:

class Project < ActiveRecord::Base
  accepts_nested_attributes_for :tasks
end

This should wrap everything inside a transaction. You then need to build the form that populates the tasks accordingly. The method tasks_attributes in your Project model is called instead of the tasks method. See the API for more information.


You might find that the AutosaveAssociation feature does what you want.

class Project < ActiveRecord::Base
  has_many :tasks, :autosave => true
end

This should wrap the save in a transaction automatically.


Before calling #save you can ask if some_project#valid? . That helps the issue if the save fails due to some_project being an invalid record, but is not a comprehensive solution.

As for the Rails' default behavior, it makes sense. Saying some_project.tasks = list_of_tasks is like saying "remove all existing tasks from some_project and assign these new ones". You are dropping the reference to the existing association Array and assigning a brand new one. This is reflected by ActiveRecord in the DB.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜