尽管在该文件中定义了Rails,但无法从文件中自动加载常量

这是一个难以解释的问题。 我在另一个模块名称空间中有一个模块,如下所示

# app/models/points/calculator.rb module Points module Calculator def self.included(base) base.send(:include, CommonMethods) base.send(:include, "Points::Calculator::#{base}Methods".constantize) end end end 

那么在其他课程中,我需要做的就是:

 class User include Points::Calculator end 

我已经在application.rb中指定了这个目录可以自动加载…(尽管我认为rails通过模型进行递归…)

 config.autoload_paths += Dir[ Rails.root.join('app', 'models', "points") ] 

在开发环境中,一切正常。 运行测试(和生产环境)时,我收到以下错误:

 Unable to autoload constant Points::Calculator, expected /Users/pete/work/recognize/app/models/points/calculator.rb to define it (LoadError) 

我实际上遵循了这里的建议来解决问题:通过在application.rb中明确要求calculator.rb, 阻止Rails在开发模式下卸载模块 。

但是,为什么会发生这种情况?

我在ActiveSupport的dependencies.rb文件中粘贴了一些调试输出,并注意到该文件需要两次。 第一次需要我可以看到常量确实已加载。

但是第二次它需要的常量已被卸载,就Rails所知,但是当调用实际的require时,ruby返回false,因为ruby知道它已经需要它。 然后Rails抛出“无法自动加载常量”错误,因为常量仍然不存在,并且ruby没有“重新要求”该文件。

任何人都可以阐明为什么会发生这种情况?

Rails增强了ruby的常量查找机制。

Ruby中的常量查找:

method missing类似,当对常量的引用无法解析时,将调用Module#constant-missing 。 当我们在给定的词法范围中引用常量时,会在以下位置搜索该常量:

 Each entry in Module.nesting Each entry in Module.nesting.first.ancestors Each entry in Object.ancestors if Module.nesting.first is nil or a module. 

当我们引用常量时,Ruby首先尝试根据此内置查找规则找到它。

ruby找不到… rails ,并使用its own lookup convention及其已经加载了哪些常量的知识(通过ruby)时,Rails会覆盖Module#const_missing以加载缺少的常量,而不需要显式的require调用程序员。

它自己的查找约定?

对比Ruby的自动加载(需要事先指定每个自动加载常量的位置),遵循将常量映射到文件名的约定。

 Points::Calculator # =>points/calculator.rb 

现在对于常量Points :: Calculator,rails在自动加载路径中搜索此文件路径(即’points / calculator.rb’),由autoload_paths配置定义。

在这种情况下,rails在其自动加载路径中搜索文件路径points/calculator ,但无法找到文件,因此显示此错误/警告。

这个答案是Urbanautomation博客的摘要。

Calculator应该是一个可以正确自动加载的

 module Points class Calculator ... end end