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'
CodePudding user response:
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 be 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 namespaces itself won't.