【问题标题】:Can I invoke a class method from an ActiveRecord::Concern without mixing it into another class?我可以从 ActiveRecord::Concern 调用一个类方法而不将它混合到另一个类中吗?
【发布时间】:2016-12-08 13:15:22
【问题描述】:

我正在创建一个ActiveSupport::Concern,它使用class_methods 方法定义了几个类方法。使用常规模块,可以直接使用NameOfModule.target_method 调用类方法(例如,在stdlib 类Math 中调用acos 很常见,就像Math.acos(x) 一样)但我不知道如何执行类似的调用我的Concern。这可能吗,如果可以,怎么做?

【问题讨论】:

    标签: ruby-on-rails ruby activesupport-concern


    【解决方案1】:

    不,您不能,因为class_methods 块中定义的方法实际上是在模块Foo::ClassMethods 中定义的(Foo 是您的问题)。这里是ActiveSupport::Concern的相关源码

    module ActiveSupport
      # ...
      module Concern
        # ...
        def class_methods(&class_methods_module_definition)
          mod = const_defined?(:ClassMethods, false) ?
            const_get(:ClassMethods) :
            const_set(:ClassMethods, Module.new)
    
          mod.module_eval(&class_methods_module_definition)
        end
      end
    end
    

    您可以看到class_methods 只是为您创建了模块ClassMethods,如果它不是您自己定义的。您定义的方法只是该模块中的实例方法,因此您不能在模块级别调用它。

    稍后,模块ClassMethods 将由包含您关注的类扩展。以下是相关源码:

    module ActiveSupport
      # ...
      module Concern
        def append_features(base)
          if base.instance_variable_defined?(:@_dependencies)
            # ...
          else
            # ...
            base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods)  # <-- Notice this line
            # ...
          end
        end
      end
    end
    

    【讨论】:

    • 感谢您的详尽解答!因此,在实践中,要测试关注点的类方法,您必须始终使用包含关注点的类。
    猜你喜欢
    • 1970-01-01
    • 2014-08-26
    • 1970-01-01
    • 1970-01-01
    • 2014-03-05
    • 1970-01-01
    • 2011-02-02
    • 2023-02-20
    • 1970-01-01
    相关资源
    最近更新 更多