3

我有一个类方法,我希望模块重载,这样模块方法可以调用 super 或其他方式来调用原始类的实现。这类似于 alias_method_chain,但问题是:是否可以通过 ActiveSupport::Concern 来实现它?

考虑以下:

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

因此,您可以在此处看到 CustomAction 类正在添加操作,并希望重载/覆盖默认的 #find 操作,以便它首先在自定义操作中查找,如果在那里找不到,则会回退到原始的 find 实现.

但是,这不起作用。将始终调用原始实现。即使您将包含放在原始#find 的定义之后也是如此。

我试图避免 alias_method_chain 因为 1) 它不是过时的吗?其中 ActiveSupport::Concern 是新的热点 2)它需要将包含放在实现下面,这有点奇怪

想法?

4

1 回答 1

0

您不能使用 ActiveSupport::Concern 覆盖类方法,因为 ActiveSupport::Concern 使用(ActiveSupport::Concern 源代码):

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

它与以下内容相同:

   class Action
      extend  CustomAction::ClassMethods
   end 

所以,你应该使用 prepend,在 Action 单个实例之前插入 CustomAction::ClassMethods。结果是:

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
于 2015-09-01T04:44:45.093 回答