启用 zeitwerk 后重新加载时未初始化的常量

发布于 2025-01-11 17:23:08 字数 1510 浏览 3 评论 0原文

在从 Classic 迁移到 Zeitwerk 时遇到一些问题。

启用 zeitwerk 并运行 rails 后,一切似乎都正常。然后,在保存 .rb 文件并刷新后,当我尝试从顶层 /lib 请求文件时,我看到了“未初始化常量”错误。

重新加载时有些配置错误,但我正在绞尽脑汁试图弄清楚细节。我的印象是拥有一个顶级 /lib 文件夹就很好,并且使用 require 加载该目录中的文件与 Zeitwerk 兼容,但现在我不这么认为当然...关于我做错了什么的想法?

注意:我目前没有设置任何特定的 eager_load_pathsautoload_paths

编辑:按照 @Xavier

[email protected]: module CustomModule autovivified from directory *********/app/workers/custom_module
[email protected]: autoload set for CustomModule::Profiler, to be loaded from *********/app/workers/custom_module/profiler.rb
[email protected]: autoload set for CustomModule::AnotherProfiler, to be loaded from *********/app/workers/custom_module/another_profiler.rb

NameError - uninitialized constant CustomModule::AttributeParser
Did you mean?  NameParserConstants:
  app/models/user.rb:180:in `first_name'
  app/middleware/catch_json_parse_errors.rb:8:in `call'
  app/middleware/decompress_requests.rb:22:in `call'

Having some trouble working out the migration from Classic to Zeitwerk.

After enabling zeitwerk and running rails s, everything seems to work. Then after saving a .rb file and refreshing, I'm seeing an "uninitialized constant" error when trying to require a file from the top level /lib.

Something is misconfigured w/ reloading, but I'm scratching my head trying to work out the details. I was under the impression that having a top level /lib folder is fine and using require to load files in that directory is compatible with Zeitwerk, but now I'm not so sure... ideas as to what I'm getting wrong?

Note: I'm not currently setting any specific eager_load_paths or autoload_paths

EDIT: updated with logging output as suggested by @Xavier

[email protected]: module CustomModule autovivified from directory *********/app/workers/custom_module
[email protected]: autoload set for CustomModule::Profiler, to be loaded from *********/app/workers/custom_module/profiler.rb
[email protected]: autoload set for CustomModule::AnotherProfiler, to be loaded from *********/app/workers/custom_module/another_profiler.rb

NameError - uninitialized constant CustomModule::AttributeParser
Did you mean?  NameParserConstants:
  app/models/user.rb:180:in `first_name'
  app/middleware/catch_json_parse_errors.rb:8:in `call'
  app/middleware/decompress_requests.rb:22:in `call'

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

萌︼了一个春 2025-01-18 17:23:08

命名空间 CustomModule 在项目中可重新加载的部分(在 app 下)以及不可重新加载的部分(在 lib 下)共享。

这个不错,支持。您只需要刻意考虑加载优先级,因为如果 lib 定义了 CustomModule::Foo 并且 Rails 认为 CustomModule 是可重新加载的,则在重新加载时没有人可以重新加载再次加载CustomModule::Foo,并且require是幂等的,所以CustomModule::Foo将不再被找到。

解决方案是确保 lib 定义命名空间,并且 Rails 自动加载器重新打开它。基本上与此处记录的相同。例如,这可以通过在初始化程序中发出 require 来从 lib 加载命名空间来完成。

这样,当自动加载器扫描文件系统时,它就知道它不负责管理 CustomModule。它会下降。如果有子常量,那么一切都会照常工作,并且这些常量将被重新加载,但名称空间本身不会。

The namespace CustomModule is shared in parts of the project that are reloadable (under app), and also in parts where is not (under lib).

This is fine, it is supported. You only need to deliberately think about load priorities, because if lib defines CustomModule::Foo and Rails believes CustomModule is reloadable, on reload nobody is loading CustomModule::Foo again, and require is idempotent, so CustomModule::Foo won't be found anymore.

The solution is to make sure lib defines the namespace, and Rails autoloaders reopen it. Essentially same as documented here. This can be done by issuing a require in an initializer that loads the namespace from lib, for example.

That way, when the autoloader scans the file system, it knows it is not responsible for managing CustomModule. It will descend. If there are child constants there everything will work as usual, and those constants will be reloaded, but the namespace itself won't.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文