Rails低冗余Concern为何导致模块丢失常量?
为什么Rails中用
concern DSL定义的模块常量无法通过constants方法获取? 先还原一下你的场景:
你最初在Rails 4.2里用传统方式定义了Orderable concern:
# app/models/concerns/orderable.rb module Orderable extend ActiveSupport::Concern COMPLETE = "Complete" end
在控制台执行Orderable.constants,返回[:COMPLETE],完全正常。
但当你改用Rails推荐的“低冗余”concern DSL写法后:
concern :Orderable do COMPLETE = "Complete" end
再执行Orderable.constants,却返回了[],找不到定义的COMPLETE常量。
问题的核心原因:常量定义的位置不同
这两种写法的本质区别,在于常量被定义在了哪个模块层级:
传统
extend ActiveSupport::Concern写法
这里的COMPLETE是直接定义在Orderable模块本身的顶层作用域里,相当于把常量直接挂在了Orderable这个模块对象上。所以调用Orderable.constants时,自然能遍历到这个常量。concernDSL写法
Rails的concern方法其实帮你做了一层封装:它会把你在块中编写的所有代码,都放到一个名为Included的内部子模块中。你可以在控制台里验证这个细节:Orderable.constants # 返回 [] Orderable::Included.constants # 返回 [:COMPLETE]Rails这么设计是为了更优雅地处理模块的包含逻辑——当其他模型
include Orderable时,Rails会自动把Included子模块里的内容注入到目标模型中,而顶层的Orderable模块只是一个“容器”,本身并不直接持有你定义的常量、方法等内容。
也就是说,你定义的COMPLETE其实没有消失,只是换了个地方“存放”而已,直接查顶层模块的常量自然找不到它。
内容的提问来源于stack exchange,提问作者aaronkelton
相关产品推荐
相关产品推荐

