4

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

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 中的保存,但这似乎也不起作用。

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

4

1 回答 1

7

我看到有两个选项:

  1. 不要after_destroy在 Condition 上使用回调,而是希望信息被破坏 Condition 的人重新计算。这是最干净的,因为您将两个独立的意图解耦:对象销毁和计算。如果有一天您想一次破坏 2 个条件并且只有在两个条件都被破坏后才重新计算,您可以看到这会更有帮助。你不能通过回调来做到这一点。它也更符合得墨忒耳法则——召唤者比条件召唤Condition.destroy者更好。info.recalculateparent.info.recalculate

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

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

    在 Condition 中,我会创建这个方法,比如 ,#destroy_without_callbacks并在其中创建destroyCondition 的子项,然后对delete自身产生条件。

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

于 2013-01-15T23:13:54.903 回答