Rails中级联删除时如何覆盖子对象默认作用域以销毁所有子项?
直接调用
Parent.find(1).destroy 就能销毁所有子对象(含软删除) 当然可以搞定这个问题!为啥原来的Parent.destroy只删默认作用域内的子对象?因为dependent: :destroy会严格遵循Child模型的默认作用域,只会查找并销毁那些标记为“未删除”(deleted_at: nil)的子记录。要让父对象销毁所有子对象,只需要修改Parent模型里的关联定义,让它绕过Child的默认作用域就行。
具体实现方案
有两种简洁的方式可以实现:
方案1:给关联绑定自定义的销毁方法
修改Parent模型的关联,给children关联添加自定义的delete_all和destroy_all方法,强制使用unscoped操作所有子记录:
class Parent < ApplicationRecord has_many :children, dependent: :destroy do def delete_all unscoped.delete_all end def destroy_all unscoped.destroy_all end end end
方案2:直接在关联上指定无作用域查询
更简单的方式是直接在has_many的作用域lambda里加上unscoped,让Parent加载子对象时直接忽略默认作用域:
class Parent < ApplicationRecord has_many :children, -> { unscoped }, dependent: :destroy end
原理说明
- 方案1通过重载关联的销毁方法,让
dependent: :destroy触发时,使用unscoped来获取所有子记录,不管它们是否被软删除,然后执行销毁操作。 - 方案2更直接,关联本身就会加载所有子对象(包括软删除的),所以
dependent: :destroy自然会把这些记录全部销毁。
这样修改后,你只需要调用Parent.find(1).destroy,就能自动销毁该父对象的所有子对象,再也不用手动写额外的unscoped.destroy_all代码啦!
内容的提问来源于stack exchange,提问作者LanceH
相关产品推荐
相关产品推荐

