有条件地覆盖 ActiveRecord 的删除机制的最佳方法是什么?

What's the best way to conditionally override ActiveRecord's deletion mechanism?

我正在尝试劫持 Rails' 删除机制,使其针对特定模型集表现不同。

ActiveRecord::Base#delete#destroy 都会返回到 ActiveRecord::Relation#delete_all,因此覆盖此方法是有意义的。

我试过了...

class MyModel < ActiveRecord::Base
  class << all
    def delete_all
      "My destruction mechanism"
    end
  end
end

...但是::all是一种每次returns不同对象的方法...

class MyModel < ActiveRecord::Base
  def self.all
    super.tap do |obj|
      class << obj
        def delete_all
          "My destruction mechanism"
        end
      end
    end
  end
end

...但是 ::all 不是 唯一 范围,无论如何都需要覆盖它...

class ActiveRecord::Relation
  def delete_all(*args)
    "My destruction mechanism"
  end
end

...但它只能适用于 MyModel 及其子类...

class ActiveRecord::Relation
  def delete_all(*args)
    if @klass.new.is_a?(MyModel)
      "My destruction mechanism"
    else
      super
    end
  end
end

...但这会导致其他模型上的堆栈溢出。

帮忙?

覆盖模型上的 deletedestroy 应该可以完成您想要的大部分内容。查看 Paranoia gem 是如何完成覆盖的。该库只有 200 行左右,并且还处理关联模型(例如,当您有 dependent: :destroy)时。