ActiveRecord(v6)中before_destroy回调未触发的原因是什么?
问题原因与解决办法
核心原因
Rails里delete和destroy是设计目的完全不同的删除方法:
delete:直接向数据库发送DELETE指令删除记录,完全跳过所有回调(包括before_destroy),也不会处理关联模型的dependent逻辑,属于纯数据库层面的快速操作,不带任何业务钩子。destroy:会先执行before_destroy这类回调方法,再按配置处理关联模型的dependent操作,最后才删除数据库记录,是包含完整业务逻辑的删除方式。
你调用的是y.delete,所以before_destroy回调自然不会触发;哪怕重写了delete方法,里面的super调用的还是原生delete逻辑,依然不会触发回调。另外你代码里self.zes.destroy_all应该是笔误,正确写法是self.zs.destroy_all。
解决办法
- 首选方案:将调用改为
y.destroy,这样会自动触发before_destroy回调,同时也会按照has_many :zs, dependent: :destroy的配置删除关联的Z记录,完全匹配你需要的业务逻辑。 - 特殊场景的妥协(不推荐):如果因特殊需求必须使用
delete且要触发回调,可以手动在delete方法里调用回调,但这违背了Rails的设计初衷,容易让后续维护者混淆逻辑:
除非有不得不使用def delete puts "in delete" run_callbacks(:destroy) do super end enddelete的硬性理由,否则强烈建议使用destroy。
内容的提问来源于stack exchange,提问作者Eric
相关产品推荐
相关产品推荐

