仅当成功保存父对象时,才将更改保存到has_many关联?

时间:2010-11-06 01:06:10

标签: ruby-on-rails activerecord

假设每个Project has_many Tasks

如果我这样做

some_project.tasks = list_of_tasks
some_project.save

即使保存失败,项目的任务也会更新。如果list_of_tasks由新记录组成,则即使保存失败,项目的任务也会删除!的 WHOA!

如果保存失败,项目应该具有与我开始搞乱之前相同的任务。我如何得到这种行为,为什么不是默认行为?

4 个答案:

答案 0 :(得分:8)

将陈述包含在交易中:

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

save!方法在出错时抛出异常,从而回滚对任务列表所做的任何更改。

如果您想更深入地了解该主题,可以阅读documentation

答案 1 :(得分:3)

我相信accepts_nested_attributes_for()将提供您想要的行为:

class Project < ActiveRecord::Base
  accepts_nested_attributes_for :tasks
end

这应该包装事务中的所有内容。然后,您需要构建相应填充任务的表单。调用Project模型中的方法tasks_attributes而不是tasks方法。有关详细信息,请参阅the API

答案 2 :(得分:3)

您可能会发现AutosaveAssociation功能符合您的要求。

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

这应该自动将保存包装在一个事务中。

答案 3 :(得分:0)

在致电#save之前,您可以询问some_project#valid?。如果由于some_project是无效记录而导致保存失败,但这不是一个全面的解决方案,那么这有助于解决问题。

至于Rails的默认行为,它是有道理的。说some_project.tasks = list_of_tasks就像是说“从some_project中删除所有现有任务并分配这些新任务”。您将删除对现有关联数组的引用并分配一个全新的关联数组。这由DB中的ActiveRecord反映出来。