Zeitwerk doesn't requires lib classes properly in Rails 6.1.6
An autoload path is a root directory, not its contents.
You need to remove the wildcards as documented here.
Rails 6 not auto-loading class properly in development (zeitwerk mode)
https://github.com/rails/rails/issues/36054
Ok so turns out that the concerns
folders are actually in the rails load paths, so it means they shouldnt be namespaced, the same way a class is app/models
isn't in the Models
namespace.
The fact that they were working in Rails 5 was some sort of side-effect that I wont get into here, but you can read about in the link above.
There is a programmatical way to detect Zeitwerk::NameError when upgrading to Rails 6?
You can check the autoload compatibility of a project with the zeitwerk::check
task:
$ bin/rails zeitwerk:check
Hold on, I am eager loading the application.
All is good!
It exercises all the autoload paths and will flag issues such as those caused by the change in constant name inference (such as those with acronyms). The task doesn't appear to be widely advertised or documented except in the upgrade guide. But, I actually use it sometimes to just flush out constant naming issues in the project generally (i.e., where the class doesn't match the file).
rails 7 zietwerk constants not found
Thanks for the updates. The problem is this glob:
config.eager_load_paths += Dir["#{config.root}/lib/**/"]
Adding to the eager load paths, adds also to the autoload paths (I find this a bit confusing, but it is how it works). Therefore, that glob is adding, for example, lib/project_name
to the autoload paths. The key observation to understand what is happening is that when there are nested root paths, the most nested one wins as far as the files and directories below that one is concerned.
So, since lib
is in the autoload paths, anything below lib
is assumed to be defined in Object
. But, since lib/project_name
is in the autoload paths too, that subtree also represents Object
. It is the same situation like the one you have in app/models
and app/models/concerns
.
These docs explain it, but they were easy to overlook in this case because it was not obvious your configuration is affected by that point.
The solution is to add only lib
:
config.autoload_paths << "#{config.root}/lib"
config.eager_load_paths << "#{config.root}/lib"
Just like that, without wildcards. Technically, the first line is redundant given the second one, but in my view this is subtle and not obvious, I personally like to make both explicit, but as you like here. (There won't be duplicated entries, the final collection passes through uniq
.)
Since we are on it, let me also comment something extra. Maybe your application already does this, but just in case, let me say that lib
has often files and directories that are not meant to be autoloaded. For example, lib/tasks
. It is clean to be deliberate about them and tell the autoloader:
Rails.autoloaders.main.ignore("#{config.root}/lib/tasks")
Otherwise, the autoloader will believe lib/tasks
is a namespace, will define an autoload for Tasks
in Object
, will eager load (== actually define) the module if eager loading is enabled, etc. Conceptually, lib/tasks
does not have code to be autoloaded/eager loaded, and the configuration has to reflect that. Same with other similar directories.
Related Topics
How Do Version Numbers Work for Mri Ruby
Declaring an Integer Range with Step != 1 in Ruby
How to Upload a File with Watir and Ie
Consequences of Implementing To_Int and To_Str in Ruby
Version Sort (With Alphas, Betas, etc.) in Ruby
Can't Get to Work Cocoapods and Yosemite
Rvm Ruby with Tk Installation (Osx)
Redirect_Uri_Mismatch. Login with Google Using Ruby on Rails
Subtract Values in Hash from Corresponding Values in Another Hash
Ruby Indented Multiline Strings
Bootstrap Datepicker Default Value Simple_Form_For
Ruby: Could Not Find a Temporary Directory
Execjs and Could Not Find a JavaScript Runtime
Capistrano 3 Change Ssh_Options Inside Task
How to Preload Concerns in a Rails Initializer Using Rails 6/Zeitwerk
Why Does Rails 4.2 + Responders Keeps Telling Me to Add Responders to the Gemfile