【问题标题】:after_destroy callback of child saves dependency of parent, causes issues when parent is destroyedchild 的 after_destroy 回调保存了 parent 的依赖,当 parent 被销毁时会导致问题
【发布时间】:2013-01-15 22:47:20
【问题描述】:

我有一种情况,我想在另一个对象被销毁后更新父对象的依赖关系。这是类层次结构的示例:

class Parent < ActiveRecord::Base
  has_one  :info, :dependent => :destroy
  has_many :conditions, :dependent => :destroy
  ....
end

class Info < ActiveRecord::Base
  belongs_to :parent

  def recalculate
    # Do stuff
  end
  ....
end

class Condition < ActiveRecord::Base
  belongs_to :parent
  has_one :condition_detail

  after_destroy :update_info

  def update_info
    parent.info.recalculate
    parent.info.save(:validate => false)
  end
  ....
end

问题是当父级被销毁时,它会破坏条件,然后触发 after_destroy 回调并在 info 对象已经被销毁后保存它。所以在父级被销毁后,信息仍然存在。如果我不绕过验证,保存将默默地失败,这是我不想要的。并使用保存!引发异常。

Condition 上的回调必须是 after_destroy,否则 Info 上的 recalculate 方法将无法正确表示关系状态来计算它需要的内容。

我觉得我需要一种在父级被销毁时绕过回调的方法,但我认为这是不可能的。我不能使用dependent => delete_all,因为这不会破坏 Condition 的孩子。我尝试查看是否有一种方法可以判断父级是否调用了 destroy 并使用该信息绕过 after_destroy 中的保存,但这似乎也不起作用。

任何帮助将不胜感激,谢谢!

【问题讨论】:

    标签: ruby-on-rails ruby rails-activerecord


    【解决方案1】:

    我看到有 2 个选项:

    1. 不要在 Condition 上使用 after_destroy 回调,而是期望信息被破坏 Condition 的人重新计算。这是最干净的,因为您将两个独立的意图解耦:对象销毁和计算。如果有一天您想一次破坏 2 个条件并且只有在两个条件都被破坏后才重新计算,您可以看到这会更有帮助。你不能通过回调来做到这一点。它还与 Law of Demeter 更紧密地对齐 - Condition.destroy 的调用者调用 info.recalculate 比 Condition 调用 parent.info.recalculate 更好。

      如果您真的想在 Condition 中打包此行为,请创建一个被调用的 #destroy_and_recalculate 函数,而不仅仅是带有某种隐藏回调的 #destroy。对于调用者来说,您将开始重新计算会更加明显。

    2. 删除父级的:condition 关联上的:dependent=&gt;destroy,并将其替换为您自己的Parent 上的before_destroy 回调,这将导致condition 在没有回调的情况下被销毁。

      在 Condition 中,我将创建此方法,例如 #destroy_without_callbacks,并在其中创建 destroy Condition 的子项,然后将条件添加到 delete 本身。

    :dependent=&gt;destroy 的功能很棒,但是对于像这样的循环,我认为迄今为止最清晰的方法是通过消除一些魔法并管理对象和进程生命周期来明确您正在做什么更明确。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-05
      • 2016-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多