5
votes

I'm trying to roll my own archiving in rails, but I'm having trouble figuring out how to alias the old destroy method before overriding it. Below is what I would like to do, but I get a NoMethodError because destroy isn't defined before that in the module. It works the way I'd expect if I put it in an InstanceMethods module, but that appears to be deprecated. Should I just handle it with a vanilla module or is there a way to do it with ActiveSupport::Concern?

module Trashable
  extend ActiveSupport::Concern

  included do
    default_scope where(deleted_at: nil)
  end

  module ClassMethods
    def deleted
      self.unscoped.where(self.arel_table[:deleted_at].not_eq(nil))
    end
  end

  alias_method :destroy!, :destroy

  def destroy
    run_callbacks(:destroy) do
      update_column(:deleted_at, Time.now)
    end
  end
end
1
Did you ever find a solution for this? - Benedikt B
@BenediktB, here is our latest version: gist.github.com/mockdeep/7574103 - lobati

1 Answers

0
votes

You are mixing a couple of things.

1 - destroy indeed does not exist in the class where you include your module before you include your module.

The long story is that the destroy method is probably generated and included for you by your ORM gem.

You can use ruby 2+ prepend to make sure your module appears after all the methods are there.

2 - You can use a vanilla module or an ActiveSupport::Concern as long as you get what you want and know what you are doing.

The point of ActiveSupport::Concern is mostly to manage modules hierarchies. If you have one level, I see no point in using it. I think mixing prepend with ActiveSupport::Concern is not a good idea.

(And after all, ActiveSupport::Concern is just plain vanilla modules in the end.)

3 - The recommended way to override a method while keeping the old is to use alias_method_chain.

You will then have a destroy_without_archive method available which will be the old way of doing it (before you overrode it).