rails 7 个 zietwerk 常量未找到

rails 7 zietwerk constants not found

我正在将我们的应用程序从 rails 6 升级到 7,我使用的是 zeitwerk 而不是带有 rails 6 的经典自动加载器,没有任何问题,现在对 [=56 没有任何更改=] 命名约定或结构它无法在 lib 文件夹中找到任何 classes/modules。我一直在调试 zeitwerk gem 并且自动加载哈希将文件路径作为键,将 [Namespace, Constant Name] 作为值,rails 6 它具有正确的名称 space,例如对于 \user\project\rails6_test\lib\folder\config.rb 中的文件,它的名称为 Folder,space 和 config.rb 中定义的 Config 将在 Folder 名称中正确找到space 但在使用 rails 7 迁移后,它总是以 Object 作为名称 space,不仅适用于顶级文件夹,而且适用于所有嵌套文件,显然它不能在 Object.

中找到这些常量

我没有看到升级指南中遗漏的任何内容,这里可能遗漏了什么?

更新

我试过 运行 bin/rails r 'pp ActiveSupport::Dependencies.autoload_paths' 但我得到以下错误,

/home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/loader/callbacks.rb:25:in `on_file_autoloaded': expected file /home/leonidas/projects/ruby_on_rails/project_name/lib/project_name/restful_resource.rb to define constant RestfulResource, but didn't (Zeitwerk::NameError)

  raise Zeitwerk::NameError.new("expected file #{file} to define constant #{cpath}, but didn't", cref.last)
  ^^^^^
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/kernel.rb:28:in `require'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/loader/helpers.rb:95:in `const_get'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/loader/helpers.rb:95:in `cget'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/loader.rb:238:in `block (2 levels) in eager_load'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/loader/helpers.rb:26:in `block in ls'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/loader/helpers.rb:18:in `each_child'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/loader/helpers.rb:18:in `ls'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/loader.rb:233:in `block in eager_load'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/loader.rb:218:in `synchronize'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/loader.rb:218:in `eager_load'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/loader.rb:318:in `each'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/loader.rb:318:in `eager_load_all'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/railties-7.0.2.2/lib/rails/application/finisher.rb:78:in `block in <module:Finisher>'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/railties-7.0.2.2/lib/rails/initializable.rb:32:in `instance_exec'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/railties-7.0.2.2/lib/rails/initializable.rb:32:in `run'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/railties-7.0.2.2/lib/rails/initializable.rb:61:in `block in run_initializers'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/3.1.0/tsort.rb:228:in `block in tsort_each'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/3.1.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/3.1.0/tsort.rb:431:in `each_strongly_connected_component_from'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/3.1.0/tsort.rb:349:in `block in each_strongly_connected_component'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/3.1.0/tsort.rb:347:in `each'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/3.1.0/tsort.rb:347:in `call'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/3.1.0/tsort.rb:347:in `each_strongly_connected_component'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/3.1.0/tsort.rb:226:in `tsort_each'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/3.1.0/tsort.rb:205:in `tsort_each'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/railties-7.0.2.2/lib/rails/initializable.rb:60:in `run_initializers'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/railties-7.0.2.2/lib/rails/application.rb:372:in `initialize!'
    from /home/leonidas/projects/ruby_on_rails/rainman/config/environment.rb:5:in `<top (required)>'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/kernel.rb:35:in `require'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/kernel.rb:35:in `require'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/railties-7.0.2.2/lib/rails/application.rb:348:in `require_environment!'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/railties-7.0.2.2/lib/rails/command/actions.rb:28:in `require_environment!'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/railties-7.0.2.2/lib/rails/command/actions.rb:15:in `require_application_and_environment!'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/railties-7.0.2.2/lib/rails/commands/runner/runner_command.rb:33:in `perform'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/thor-1.2.1/lib/thor/command.rb:27:in `run'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/thor-1.2.1/lib/thor/invocation.rb:127:in `invoke_command'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/thor-1.2.1/lib/thor.rb:392:in `dispatch'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/railties-7.0.2.2/lib/rails/command/base.rb:87:in `perform'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/railties-7.0.2.2/lib/rails/command.rb:48:in `invoke'
    from /home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/railties-7.0.2.2/lib/rails/commands.rb:18:in `<top (required)>'
    from bin/rails:4:in `require'
    from bin/rails:4:in `<main>'

我的 application.rb 中有 config.autoload_paths << "#{config.root}/lib",为了使用 zeitwerk 测试预加载,我添加了 config.eager_load_paths += Dir["#{config.root}/lib/**/"],如果您需要更多信息,请告诉我。

更新 2

/lib 运行 bin/rails r 'pp ActiveSupport::Dependencies.eager_load_paths' 去掉通配符后得到以下输出

["/home/leonidas/projects/ruby_on_rails/project_name/lib",
 "/home/leonidas/projects/ruby_on_rails/project_name/lib/",
 "/home/leonidas/projects/ruby_on_rails/project_name/lib/project_name/",
 "/home/leonidas/projects/ruby_on_rails/project_name/lib/project_name/microservices/",
 "/home/leonidas/projects/ruby_on_rails/project_name/lib/project_name/microservices/dir/",
 "/home/leonidas/projects/ruby_on_rails/project_name/lib/project_name/dir/",
 "/home/leonidas/projects/ruby_on_rails/project_name/lib/project_name/dir/dir/",
 "/home/leonidas/projects/ruby_on_rails/project_name/lib/project_name/dir/dir/dir/",
 "/home/leonidas/projects/ruby_on_rails/project_name/lib/project_name/dir/dir/dir/dir/",
 "/home/leonidas/projects/ruby_on_rails/project_name/lib/project_name/dir/dir/dir/dir/dir/",
 "/home/leonidas/projects/ruby_on_rails/project_name/lib/project_name/dir/dir/",
 "/home/leonidas/projects/ruby_on_rails/project_name/lib/project_name/dir/",
 "/home/leonidas/projects/ruby_on_rails/project_name/lib/project_name/dir/",
 "/home/leonidas/projects/ruby_on_rails/project_name/lib/project_name/dir/",
 "/home/leonidas/projects/ruby_on_rails/project_name/lib/tasks/",
 "/home/leonidas/projects/ruby_on_rails/project_name/app/controllers",
 "/home/leonidas/projects/ruby_on_rails/project_name/app/mailers",
 "/home/leonidas/projects/ruby_on_rails/project_name/app/models",
 "/home/leonidas/projects/ruby_on_rails/project_name/app/serializers",
 "/home/leonidas/projects/ruby_on_rails/project_name/app/workers",
 "/home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/actionmailbox-7.0.2.2/app/controllers",
 "/home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/actionmailbox-7.0.2.2/app/jobs",
 "/home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/actionmailbox-7.0.2.2/app/models",
 "/home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/activestorage-7.0.2.2/app/controllers",
 "/home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/activestorage-7.0.2.2/app/controllers/concerns",
 "/home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/activestorage-7.0.2.2/app/jobs",
 "/home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/activestorage-7.0.2.2/app/models",
 "/home/leonidas/projects/ruby_on_rails/project_name/spec/mailers/previews"]

和运行 bin/rails r 'pp ActiveSupport::Dependencies._eager_load_paths'输出以下

{"/home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/activestorage-7.0.2.2/app/controllers",
  "/home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/activestorage-7.0.2.2/app/controllers/concerns",
  "/home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/activestorage-7.0.2.2/app/jobs",
  "/home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/activestorage-7.0.2.2/app/models",
  "/home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/actionmailbox-7.0.2.2/app/controllers",
  "/home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/actionmailbox-7.0.2.2/app/jobs",
  "/home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/actionmailbox-7.0.2.2/app/models",
  "/home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/actiontext-7.0.2.2/app/helpers",
  "/home/leonidas/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/actiontext-7.0.2.2/app/models",
  "/home/leonidas/projects/ruby_on_rails/project_name/app/controllers",
  "/home/leonidas/projects/ruby_on_rails/project_name/app/mailers",
  "/home/leonidas/projects/ruby_on_rails/project_name/app/models",
  "/home/leonidas/projects/ruby_on_rails/project_name/app/serializers",
  "/home/leonidas/projects/ruby_on_rails/project_name/app/workers",
  "/home/leonidas/projects/ruby_on_rails/project_name/lib"}

我正在查看 rails 中的 zeitwerk.rake 任务,它似乎不检查自动加载路径中存在的任何现有目录和非空目录,但不在急切加载路径中,我不明白这里应该发生什么,autoload_paths 不应该有扩展的文件夹结构并且只列出根文件夹吗?因为在我的例子中,自动加载也有嵌套的目录,并且 eager_load 只有根目录正在打印关于不检查 lib 中的文件夹的警告。

感谢您的更新。问题是这个 glob:

config.eager_load_paths += Dir["#{config.root}/lib/**/"]

添加到预加载路径,也添加到自动加载路径(我觉得这有点令人困惑,但它是如何工作的)。因此,该 glob 正在将 lib/project_name 添加到自动加载路径。理解正在发生的事情的关键观察是,当存在嵌套的根路径时,the most nested one wins 就其下方的文件和目录而言。

因此,由于 lib 在自动加载路径中,因此假定 lib 以下的任何内容都在 Object 中定义。但是,由于 lib/project_name 也在自动加载路径中,该子树也代表 Object。这与您在 app/modelsapp/models/concerns.

中遇到的情况相同

These docs 解释一下,但在这种情况下它们很容易被忽略,因为您的配置受该点影响并不明显。

解决方法是只添加lib:

config.autoload_paths << "#{config.root}/lib"
config.eager_load_paths << "#{config.root}/lib"

就这样,没有通配符。从技术上讲,相对于第二行,第一行是多余的,但在我看来,这是微妙且不明显的,我个人喜欢将两者都明确化,但如您所愿。 (不会有重复条目,最终集合通过uniq。)

既然我们在上面,让我也评论一些额外的东西。也许您的应用程序已经这样做了,但为了以防万一,让我说 lib 通常有不打算自动加载的文件和目录。例如,lib/tasks。仔细考虑它们并告诉自动加载器是干净的:

Rails.autoloaders.main.ignore("#{config.root}/lib/tasks")

否则,自动加载器将认为 lib/tasks 是一个命名空间,将为 TasksObject 中定义一个自动加载,如果是急切的,将急切加载(==实际定义)模块加载已启用等。从概念上讲,lib/tasks 没有要加载的代码 autoloaded/eager,配置必须反映这一点。与其他类似目录相同。