为什么 Rails 低 cruft 问题会导致模块失去其常量?

Why does the Rails low-cruft concern cause the module to lose its constants?

提问人:aaronkelton 提问时间:5/4/2018 更新时间:5/4/2018 访问量:92

问:

我在 Rails 4.2 中有一个 Orderable 问题,常量为 “Complete”。:app/models/concerns/orderable.rb

module Orderable
  extend ActiveSupport::Concern
  COMPLETE = "Complete"
end

在 Rails 控制台中,我能够运行 ,它返回 .但是,如果我将 Orderable 关注点更改为 Rails 相关模块中描述的“低粗制滥造”样式,如下所示:Orderable.constants[:COMPLETE]

concern :Orderable do
  COMPLETE = "Complete"
end

然后在 Rails 控制台中运行返回 .Rails 文档说,“定义关注点的低粗制滥造的捷径......是等价的。为什么这个单一的更改会产生失去对模块常量的访问的影响?我需要以某种方式重新定义它们吗?Orderable.constants[]

Ruby-on-Rails 模块 关注点分离 activesupport-concern

评论


答:

1赞 max 5/4/2018 #1

实际上,这似乎是关注“宏观”实现方式的一个缺陷:

require 'active_support/concern'

class Module
    # A low-cruft shortcut to define a concern.
    #
    #   concern :EventTracking do
    #     ...
    #   end
    #
    # is equivalent to
    #
    #   module EventTracking
    #     extend ActiveSupport::Concern
    #
    #     ...
    #   end
    def concern(topic, &module_definition)
      const_set topic, Module.new {
        extend ::ActiveSupport::Concern
        module_eval(&module_definition)
      }
    end
  end
  include Concerning
end

此代码对 ruby Module 对象进行 monkeypatch 以提供方法。concern

这里的关键是,在定义的新模块的上下文中,它没有正确评估块。module_eval(&module_definition)

运行时实际发生的情况:

concern :Orderable do
  COMPLETE = "Complete"
end

::COMPLETE
# => "Complete"

是你在主对象中声明常量。哎呀!COMPLETE

为了正常工作,它应该看起来像这样:

def concern(topic, &module_definition)
  const_set topic, Module.new do |m|
    extend ::ActiveSupport::Concern
    m.module_eval(&module_definition)
  end
end

在解决这个问题之前,我会避免使用“low-cruft”语法。