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

假设每个Project都有很多Tasks

如果我做

 some_project.tasks = list_of_tasks some_project.save 

即使保存失败,项目的任务也会更新。 如果list_of_tasks包含新记录,即使保存失败,项目的任务也会被删除哇!

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

将语句包含在事务中:

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

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

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

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

 class Project < ActiveRecord::Base accepts_nested_attributes_for :tasks end 

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

您可能会发现AutosaveAssociationfunction可以满足您的需求。

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

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

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

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