Sub*_*ash 5 ruby autoload zeitwerk ruby-on-rails-7
我正在将我们的应用程序从 Rails 6 升级到 7,我使用 zeitwerk 而不是 Rails 6 的经典自动加载器,没有任何问题,现在没有对文件夹/文件命名约定或结构进行任何更改,它无法在其中找到任何类/模块lib 文件夹。我一直在调试 zeitwerk gem 和自动加载哈希将文件路径作为键和[Namespace, Constant Name]值,在 Rails 6 中它具有正确的名称空间,例如,对于其中的文件\user\project\rails6_test\lib\folder\config.rb作为Folder名称空间并Config在内部定义config.rb将被正确找到在Folder名称空间中,但在使用 Rails 7 迁移之后,它始终具有Object名称空间,不仅适用于顶级文件夹,而且适用于所有嵌套文件,显然它无法在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>'
Run Code Online (Sandbox Code Playgroud)
我config.autoload_paths << "#{config.root}/lib"在我的 application.rb 中添加了 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"]
Run Code Online (Sandbox Code Playgroud)
并运行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"}
Run Code Online (Sandbox Code Playgroud)
我正在研究zeitwerk.rakeRails 中的任务,它似乎没有检查自动加载路径中存在的任何现有目录和非空目录,但不在急切加载路径中,我不明白这里应该发生什么,不autoload_paths应该具有展开的文件夹结构并且仅列出根文件夹?因为在我的例子中,自动加载也具有嵌套目录,而 eager_load 仅具有根目录正在打印有关不检查 lib 内的文件夹的警告。
感谢您的更新。问题是这个全局:
config.eager_load_paths += Dir["#{config.root}/lib/**/"]
Run Code Online (Sandbox Code Playgroud)
添加到急切加载路径,还添加到自动加载路径(我发现这有点令人困惑,但这就是它的工作原理)。lib/project_name因此,该 glob 正在添加到自动加载路径等。了解正在发生的情况的关键观察是,当存在嵌套根路径时,就该根路径下面的文件和目录而言,最嵌套的根路径获胜。
因此,由于lib位于自动加载路径中,因此lib假定以下任何内容都在 中定义Object。但是,由于lib/project_name也在自动加载路径中,因此该子树也代表Object. app/models这与您在和中遇到的情况相同app/models/concerns。
这些文档对此进行了解释,但在这种情况下很容易被忽视,因为您的配置受该点影响并不明显。
解决方案是仅添加lib:
config.autoload_paths << "#{config.root}/lib"
config.eager_load_paths << "#{config.root}/lib"
Run Code Online (Sandbox Code Playgroud)
就像这样,没有通配符。从技术上讲,第一行相对于第二行来说是多余的,但在我看来,这是微妙且不明显的,我个人喜欢将这两行都明确化,但正如您所喜欢的那样。(不会出现重复条目,最终集合通过uniq。)
既然我们已经讨论过了,那么让我也发表一些额外的评论。也许您的应用程序已经做到了这一点,但为了以防万一,让我说它lib经常有不应该自动加载的文件和目录。例如,lib/tasks。仔细考虑它们并告诉自动加载器是很干净的:
Rails.autoloaders.main.ignore("#{config.root}/lib/tasks")
Run Code Online (Sandbox Code Playgroud)
否则,自动加载器将认为是一个命名空间,将为inlib/tasks定义一个自动加载,如果启用了预加载,则将预加载(==实际定义)模块,等等。从概念上讲,没有要自动加载/预加载的代码,并且配置必须反映这一点。与其他类似目录相同。TasksObjectlib/tasks
| 归档时间: |
|
| 查看次数: |
5420 次 |
| 最近记录: |