【问题标题】:Save changes to a has_many association ONLY when you successfully save the parent object?仅当您成功保存父对象时才保存对 has_many 关联的更改?
【发布时间】:2016-08-16 18:42:44
【问题描述】:

假设每个Projecthas_manyTasks。

如果我这样做

some_project.tasks = list_of_tasks
some_project.save

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

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

【问题讨论】:

    标签: ruby-on-rails activerecord


    【解决方案1】:

    将语句包含在事务中:

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

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

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

    【讨论】:

    • 这行得通,但是这种方法意味着每当我在整个应用程序中更新任务时,我都必须记住将其包装在事务中(我相信我会忘记的)。如果我能以 DRY 方式将此行为封装在 Project 模型中会更好。
    • 好吧,定义一个方法 replace_tasks(new_tasks) 就可以了
    【解决方案2】:

    我相信accepts_nested_attributes_for() 会提供你想要的行为:

    class Project < ActiveRecord::Base
      accepts_nested_attributes_for :tasks
    end
    

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

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

        • 这不起作用。 some_project.tasks = list_of_tasks 会在调用现有任务列表时立即清除它,无论我何时或是否调用some_project.save。我真的不敢相信这是默认行为——这真的违反直觉!
        • "说some_project.tasks = list_of_tasks 就像说"从 some_project 中删除所有现有任务并分配这些新任务""。我认为这更像是说“从some_project 中删除所有现有任务并分配这些新任务当我保存some_project。some_project.name = "whatever" 在我保存之前不会生效,@987654331 也不应该生效@
        • @HoraceLoeb:不同的野兽,不同的规则。 IIRC,大多数 ORM 都遵循这个推理,因为它比你预期的行为更容易实现(相信我,你不是第一个想出这个的人)。无法确定来源,抱歉。
        猜你喜欢
        • 2014-12-26
        • 2012-08-25
        • 1970-01-01
        • 1970-01-01
        • 2012-07-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多