为什么Rails低失误会导致模块失去常量?

时间:2018-05-03 23:46:16

标签: ruby-on-rails module separation-of-concerns activesupport-concern

我在Rails 4.2中有一个可订购的问题,有一个常数" Complete"。 app/models/concerns/orderable.rb

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

在Rails控制台中,我可以运行Orderable.constants,返回[:COMPLETE]。但是,如果我将可订购的问题更改为" low-cruft" Rails concerning module中描述的样式如此:

concern :Orderable do
  COMPLETE = "Complete"
end

然后在Rails控制台中运行Orderable.constants返回[]。 Rails的文档说明,用来定义问题的"低空缺口捷径是等价的。"为什么这种单一变化会导致失去对模块常量的访问?我需要以某种方式重新定义它们吗?

1 个答案:

答案 0 :(得分: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

此代码monkeypat the ruby​​ Module对象以提供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”语法。