1

如何覆盖模型关注点中定义的类方法?

这有点棘手,因为您并没有真正覆盖类方法,对吗?class_methods因为它使用了在块中定义类方法的关注api 。

所以说我有一个看起来像这样的问题:

module MyConcern
  extend ActiveSupport::Concern

  class_methods do
    def do_something
       #some code
    end
  end

end

在模型中..我将如何覆盖该方法,以便在使用继承时可以像使用 super 一样调用它?所以在我的模型中,我想去:

def self.do_something
  #call module do_something
end

?

4

3 回答 3

3

如果您在定义的模型中使用了included ,则应该能够使用:MyConcernself.do_somethingsuper

module MyConcern
  extend ActiveSupport::Concern

  class_methods do
    def do_something
      puts "I'm do_something in the concern"
    end
  end
end

class UsesMyConcern < ActiveRecord::Base
  include MyConcern

  def self.do_something
    super
  end
end

UsesMyConcern.do_something
# => "I'm do_something in the concern"

如果您没有或不想include MyConcern在模型中使用,并且想要do_something在不创建任何中间对象的情况下调用模块,则可以将模型更改为:

class UsesMyConcern < ActiveRecord::Base
  def self.do_something                
    MyConcern::ClassMethods.instance_method(:do_something).bind(self).call
  end
end

UsesMyConcern.do_something
# => "I'm do_something in the concern"

ActiveSupport::Concern.class_methods如果还没有模块,则在关注点中定义一个ClassMethods模块,这就是我们可以找到该do_something方法的地方。

于 2016-07-24T12:23:16.020 回答
1

为什么不简单地调用模块的方法:MyConcern.do_something

我不确定super模块是否容易做(尽管我知道为什么这可能有用)。

下一个最佳解决方案可能是使用以下方法调用#included_modules和手动迭代#responds_to?

def self.do_something
  self.super_module(__method__)
end

def self.super_module(method)
  self.included_modules.find { |m| m.responds_to? method }.public_send(method)
end
于 2016-07-21T20:39:30.593 回答
0

使用旧方式alias_method_chainhttps ://ernie.io/2011/02/03/when-to-use-alias_method_chain/

新方法(需要> ruby​​ 2.0.0)你真的应该使用它,因为在rails 5.0中使用它时会有一个弃用警告:http: //paweljaniak.co.za/2014/09/30/understanding-ruby -模块前置和包含/

于 2016-07-21T13:56:19.847 回答