PJSCopeland
PJSCopeland

Reputation: 3006

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

I am trying to hijack Rails' deletion mechanism to make it behave differently for a certain set of models.

Both ActiveRecord::Base#delete and #destroy lead back to ActiveRecord::Relation#delete_all, so it would make sense to override this method.

I have tried...

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

... but ::all is a method that returns a different object every time...

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

... but ::all isn't the only scope that needs it overridden anyway...

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

... but it can only apply to MyModel and its subclasses...

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

... but this causes stack overflows on other models.

Help?

Upvotes: 1

Views: 392

Answers (1)

Kristj&#225;n
Kristj&#225;n

Reputation: 18803

Overriding delete and destroy on your model should accomplish most of what you want. Check out how the Paranoia gem accomplishes its overriding. The library's only 200 lines or so, and also handles associated models (eg when you have dependent: :destroy).

Upvotes: 1

Related Questions