Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails Rails无法从文件中自动加载常量,尽管该文件中定义了常量_Ruby On Rails_Ruby_Autoload - Fatal编程技术网

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