Ruby on rails Rails无法从文件中自动加载常量,尽管该文件中定义了常量
这是一个很难解释的问题。我在另一个模块命名空间中有一个模块,如下所示:Ruby on rails Rails无法从文件中自动加载常量,尽管该文件中定义了常量,ruby-on-rails,ruby,autoload,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)
# 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中指定了这个目录为autoloadable…(尽管我认为rails通过模型递归…)
在developmentenv中,一切正常。运行测试(和生产环境)时,出现以下错误:
Unable to autoload constant Points::Calculator, expected /Users/pete/work/recognize/app/models/points/calculator.rb to define it (LoadError)
实际上,我按照这里的建议解决了这个问题:在application.rb中显式地要求calculator.rb
然而,为什么会发生这种情况
我在ActiveSupport的dependencies.rb文件中插入了一些调试输出,并注意到这个文件需要两次。第一次需要时,我可以看到常量确实被加载了
但是第二次调用require时,就Rails所知,常量已经被卸载,但是当调用实际require时,ruby返回false,因为ruby知道它已经需要它了。然后Rails抛出“无法自动加载常量”错误,因为常量仍然不存在,ruby也没有“重新要求”该文件
有人能解释为什么会发生这种情况吗?
Calculator
应该是一个类才能正确自动加载
module Points
class Calculator
...
end
end
Rails增强了ruby的常量查找机制 Ruby中的常量查找: 与
方法缺失
类似,当对常量的引用无法解析时,将调用模块#常量缺失
。当我们在给定的词汇范围中引用一个常量时,该常量将在以下位置搜索:
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发挥了作用,它使用自己的查找约定以及关于哪些常量已经被加载的知识(ruby),rails覆盖模块const missing来加载丢失的常量,而不需要程序员显式地调用require
它自己的查找约定?
与Ruby的autoload(要求预先指定每个自动加载常量的位置)不同,rails遵循将常量映射到文件名的约定
Points::Calculator # =>points/calculator.rb
现在,对于常量Points::Calculator,rails在自动加载路径中搜索该文件路径(即'Points/Calculator.rb'),该路径由autoload_path
配置定义
在这种情况下,rails在其自动加载的路径中搜索文件路径点/calculator
,但未能找到文件,因此显示此错误/警告
这个答案是对此的抽象
编辑:
我写了一篇关于Zeitwerk的博客,Zeitwerk是Rails中新的代码重新加载程序。查看->如果有人在rails 6中遇到此问题,该rails 6具有
zeitwerk
autoloader
将应用程序中的ruby常量查找更改回classic。rb
# config/application.rb
#...
config.autoloader = :classic
#...
请在此阅读更多详细信息对不起,我描述错了,它是模块中的一个模块…我已经更新了上面的描述以更加准确…它是一个模块这一事实是否会影响自动加载?在这种情况下,我建议将文件放在
lib
目录中,而不是app/models
lib用于非特定于应用程序的库,因此,我把这个应用程序/。然而,我可以看到一个论点,将其放在app/lib或app/concerns或app/models/concerns目录中。是的,app/models/concerns
可能是最好的地方。从丢失的自动加载路径中删除点有帮助吗?这应该不是必需的是的,我在自动加载路径中尝试过有无。同样的问题。似乎也有同样的问题。因为我有30多个这样的课程,所以我不得不要求上课,这很烦人。事实上,我已经看过这篇文章了,谢谢你的解释。但是,文件存在并且正确加载了一次,但是如上所述,我可以看到它需要两次,在第二次循环中,常量已经卸载。我不清楚你的解释是如何说明这个事实的。
# config/application.rb
#...
config.autoloader = :classic
#...