3
votes

I have a class method that I would like a module to overload, such that the modules method can call super or another way to call the original class's implementation. This is similar to alias_method_chain, but the question is: is it possible to implement this via ActiveSupport::Concern?

Consider the following:

module CustomAction
  CUSTOM_ACTIONS = {custom_action_one: "c1", custom_action_two: "c2"}

  include ActiveSupport::Concern
  module ClassMethods
    def find(id)
      CUSTOM_ACTIONS[id] || super
    end
  end
end

class Action
  include CustomAction

  ACTIONS = {action_one: "1", action_two: "2"}

  def self.find(id)
     ACTIONS[id]
  end
end

So you can see here that the CustomAction class is adding actions and wants to overload/override the default #find action such that it looks up first in custom actions and if it doesn't find it there, will then fallback to the original find implementation.

However, this doesn't work. The original implementation will always be called. This is the case even if you put the include after the definition of the original #find.

I'm trying to avoid alias_method_chain because 1) isn't it outdated? where ActiveSupport::Concern is the new hotness 2) It would require having the include placed below the implementation which is kind of weird

Thoughts?

1

1 Answers

0
votes

You cannot use ActiveSupport::Concern to override class method , because ActiveSupport::Concern use (ActiveSupport::Concern source code) :

base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods)

It is same as :

   class Action
      extend  CustomAction::ClassMethods
   end 

So , you should use prepend , insert CustomAction::ClassMethods before Action single instance . The result is :

module CustomAction
  CUSTOM_ACTIONS = {custom_action_one: "c1", custom_action_two: "c2"}

  module ClassMethods
    def find(id)
      CUSTOM_ACTIONS[id] || super
    end
  end
end

class Action

  ACTIONS = {action_one: "1", action_two: "2"}

  def self.find(id)
     ACTIONS[id]
  end

  #prepend on the Action single instance , not on the instance
  class << self 
    prepend CustomAction::ClassMethods
  end  
end