I'm upgrading our app from rails 6 to 7, I was using zeitwerk instead of the classic autoloader with rails 6 without any issues, now without any changes to the folder/file naming convention or structure it fails to find any classes/modules inside lib folder. I've been debugging the zeitwerk gem and the autoloads hash has file paths as keys and [Namespace, Constant Name]
as the value, with rails 6 it had correct name space, e.g. for a file in \user\project\rails6_test\lib\folder\config.rb
it'd have Folder
as the namespace and Config
defined inside config.rb
would be found correctly in Folder
namespace but after the migration with rails 7 it always has Object
as the namespace, not just for top level folders but for all nested files and obviously it can't find those constants in the Object
.
I don't see anything that I missed from the upgrade guide, what could be missing here ?
Update
I tried running bin/rails r 'pp ActiveSupport::Dependencies.autoload_paths'
and I get the error below,
/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>'
I have config.autoload_paths << "#{config.root}/lib"
in my application.rb and to test eager loading with zeitwerk I add config.eager_load_paths += Dir["#{config.root}/lib/**/"]
, let me know if you need any more info.
Update 2
After getting rid of the wildcard with just /lib
running bin/rails r 'pp ActiveSupport::Dependencies.eager_load_paths'
gives me the following output
["/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"]
and running bin/rails r 'pp ActiveSupport::Dependencies._eager_load_paths'
outputs the following
{"/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"}
I was looking into the zeitwerk.rake
task in rails and it seems it doesn't check any existing and non empty directories that exist in autoload paths but not in the eager load paths, I don't understand what should be happening here, is autoload_paths
not supposed to have the expanded folder structure and only list root folders ? because in my case autoload having nested dirs too and eager_load only having root dirs is printing that warning about not checking the folders inside lib.
/home/leonidas/projects/ruby_on_rails/project_name/lib/project_name/restful_resource.rb
defineRestfulResource
? – Choroidmodule ProjectName; class RestfulResource; end; end
– Makeyevka