启用 zeitwerk 后重新加载时未初始化的常量
在从 Classic 迁移到 Zeitwerk 时遇到一些问题。
启用 zeitwerk 并运行 rails
后,一切似乎都正常。然后,在保存 .rb 文件并刷新后,当我尝试从顶层 /lib
请求文件时,我看到了“未初始化常量”错误。
重新加载时有些配置错误,但我正在绞尽脑汁试图弄清楚细节。我的印象是拥有一个顶级 /lib
文件夹就很好,并且使用 require
加载该目录中的文件与 Zeitwerk 兼容,但现在我不这么认为当然...关于我做错了什么的想法?
注意:我目前没有设置任何特定的 eager_load_paths
或 autoload_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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
命名空间
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 (underapp
), and also in parts where is not (underlib
).This is fine, it is supported. You only need to deliberately think about load priorities, because if
lib
definesCustomModule::Foo
and Rails believesCustomModule
is reloadable, on reload nobody is loadingCustomModule::Foo
again, andrequire
is idempotent, soCustomModule::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 arequire
in an initializer that loads the namespace fromlib
, 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.