Zeitwerk, Rails, and path-based gems

We’ve been working on upgrading from rails 5 to rails 6. In preparation we’ve been setting up a number of gems that we use to load themselves with zeitwerk. The issue is that the rails zeitwerk loader is eager loading the gems in our directories!

This is strange to me because my understanding was the zeitwerk should be workable with multiple loaders and allowing each gem to own it’s own directory. However, we’re seeing that the zeitwerk loader is ignoring the configuration in each of the gems and just autoloading the gems themselves.

How can we prevent rails from doing this?

It is not the loaders, it is Rails itself.

If eager loading is enabled, Rails tells all loaders registered in the process to eager load using Zeitwerk::Loader.eager_load_all.

You can tell your loader to not eager load parts of the gem with Zeitwerk::Loader#do_not_eager_load.

The idea here was that all of your gem is loadable by the user regardless of this setting anyway, you don’t control that. Users can autoload as much from your gem as they want because the code is reachable. So, with this setting they autoload it all (but exceptions) to leverage copy-on-write.

Did this cause a problem in your project, or was just unexpected?

We kept looking at it since I posted and it must be something to do with how that works with collapse which we were using. At the crux were 2 EachValidators and they were in a nested directory but without any namespacing (which seems necessary for how they work).

The collapse was working correctly in rails 5 but with the rails 6 upgrade it was attempting to eagerload from these files with the namespace. We ended up remove the collapse calls, ignoring the file path, and manually requiring the files.

This was broken with both :classic and :zeitwerk modes.

That seems strange.

classic mode does not have the notion of “collapsing”, in what sense was collapsing working in Rails 5?

The message above mentioned multiple loaders. Which are the multiple loaders involved here?

Can you provide a few details about where are these files located and which loader is managing them?