我有一种情况,我希望在另一个对象被销毁后更新父对象的依赖关系。以下是类层次结构的示例:
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回调并在信息对象被销毁后保存它。所以在父母被破坏后,信息仍然存在。如果我没有绕过验证,保存将无声地失败,这是我不想要的。并使用保存!提出异常。
Condition上的回调必须是after_destroy,否则Info上的重新计算方法将无法正确表示关系状态以计算它需要的内容。
我觉得在父母被摧毁时我需要一种绕过回调的方法,但我认为这是不可能的。我不能使用dependent =&gt; delete_all因为它不会破坏Condition的子节点。我试过看看是否有一种方法可以判断父母是否已经对其进行了销毁并使用该信息来绕过after_destroy中的保存,但这似乎也没有用。
非常感谢任何帮助,谢谢!
答案 0 :(得分:7)
我看到有两个选项:
不要在条件上使用after_destroy
回调,而是期望任何正在销毁条件的人重新计算信息。这是最干净的,因为你将两个独立的意图分离:对象破坏和计算。如果有一天你想要一次破坏2个条件并且只有在两个条件被销毁之后才重新计算,你可以看到这会更有用。你不能通过回调来做到这一点。它还与Law of Demeter更紧密地对齐 - 调用Condition.destroy
info.recalculate
的调用者优于调用parent.info.recalculate
的条件。
如果您确实想要在Condition中打包此行为,请创建一个被调用的#destroy_and_recalculate
函数,而不仅仅是#destroy
,其中包含一系列隐藏的回调。对于呼叫者来说,您将开始重新计算更为明显。
删除父级:dependent=>destroy
关联中的:condition
,并将其替换为before_destroy
上Parent
的回调,这将导致condition
成为#destroy_without_callbacks
在没有回调的情况下被摧毁。
在条件方面,我会创建此方法,例如destroy
,并在其中delete
条件的子项,然后将条件设置为:dependent=>destroy
本身。
{{1}}的功能很棒,但是对于像这样的循环,我认为迄今为止最清晰的方法是通过消除一些魔法并管理对象来明确你所做的事情。更明确地处理生命周期。