before_destroy用于销毁依赖记录的模型

时间:2015-11-19 16:28:35

标签: ruby-on-rails activerecord

我有这样的情况:

class Shop < ActiveRecord::Base
  has_many :services, dependent: :destroy
end

class Service < ActiveRecord::Base
  has_many :model_weeks, dependent: :destroy
end

class ModelWeek < ActiveRecord::Base
  before_destroy :prevent_destroy, if: :default?

  private

  def prevent_destroy
    false
  end
end

当我试图销毁一家商店时,我得到ActiveRecord::RecordNotDestroyed: Failed to destroy the record,因为它首先开始销毁相关的记录,并且它被模型周期中的回调阻止了。

我可以在销毁商店时轻松取消设置ModelWeek的默认设置,只有当我能抓住它时。 before_destroy模型中的Shop在引发上述异常之前不会被触发。

那么,有没有办法在Shop模型中捕获这个,或者如果没有,是否有可能&#34;知道&#34;在ModelWeek中,父母是否触发了破坏?我调查解析调用者,但它没有提供任何有用的东西,反正它会很麻烦......

3 个答案:

答案 0 :(得分:1)

经过一些研究和测试,这就是我想出来的:

这是调用方法的顺序(do_before_destroybefore_destroy回调中指定的任何方法):

  • Shop.destroy
  • Service.destroy
  • ModelWeek.destroy
  • ModelWeek.do_before_destroy
  • Service.do_before_destroy
  • Shop.do_before_destroy

所以,我可以在父母的破坏方法(Shop)中处理任何阻止儿童(ModelWeek)破坏的事情:

# Shop
def destroy
  # default is a scope
  ModelWeek.default.where(service_id: self.services.pluck(:id)).each do |m| 
    m.unset_default 
  end

  super
end

之后没有任何东西可以阻止孩子的破坏,而且连锁店继续不受欢迎。

更新

有更好,更清晰的解决方案,无需覆盖父级的destroy并进行任何查询:

class Shop < ActiveRecord::Base
  has_many :services, dependent: :destroy, before_remove: :unset_default_week

  private

  def unset_default_week(service)
    service.model_weeks.default.unset_default
  end
end

答案 1 :(得分:0)

由于rails有从相关孩子到父母的破坏链,这真的很有道理,对吧?为了方便起见,我们可以在ModelWeek中覆盖destroy方法,如下所示:

class ModelWeek < ActiveRecord::Base
  # before_destroy :prevent_destroy, if: :default?
  def destroy
    unless default?
      super
    end
  end
end

答案 2 :(得分:0)

我通过使用有趣的黑客来解决这个问题, 你只需要放before_destroy行 在关联线之前 并且在删除关联之前它将运行before_destroy