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

时间:2014-07-03 05:29:06

标签: ruby-on-rails ruby autoload

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

# 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)

我实际上遵循了这里的建议来解决问题:Stop Rails from unloading a module in development mode通过在application.rb中明确要求calculator.rb。

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

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

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

有人能说清楚为什么会这样吗?

3 个答案:

答案 0 :(得分:7)

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在autoload_paths配置定义的自动加载路径中搜索此文件路径(即'points / calculator.rb')。

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

这个答案是这个Urbanautomation blog的摘要。

答案 1 :(得分:0)

Calculator应该是才能正确自动加载

module Points
  class Calculator
  ...
  end
end

答案 2 :(得分:-1)

如果有人在具有zeitwerk自动加载器的rails 6中遇到此问题,

在您的application.rb中将ruby常量查询更改回经典

# config/application.rb
#...
config.autoloader = :classic
#...

在此处Rails Official Guides

了解更多详细信息