Rails 6 introduced a new autoloader called Zeitwerk. While it has many many improvements, one of the main changes is how strict it is with filenames and the constants they define. Unless you have full coverage on your application (few apps actually reach 100%) it can be quite easy to end up with an app that won't boot in your staging/production environment.
This is a welcome change from me, I believe it leads to much more stable and predictable codebases when the filenames and constants match 1:1. This can become an issue for anyone used to working with the rails classic autoloader since that allowed developers to get away with mostly anything inside their files.
Adding the following spec to any new rails 6+ project will protect from such problems, as the autoloading will be triggered in the CI environment instead; before merge and deploy. This is also perfect if you're upgrading any older Rails 5 apps and you're nervous about switching to the new autoloader.
# spec/zeitwerk_spec.rb
require 'rails_helper'
describe 'Zeitwerk' do
it 'eager loads all files' do
expect do
Zeitwerk::Loader.eager_load_all
end.to_not raise_error
end
end
Original reference post for code snippet Rails 6 and Rspec : How to test Zeitwerk mode by Matthieu Varagnat
You can take this a step further on CI and have a dedicated job that runs specifically to check the autoloading. This can be dne before the tests (to avoid wasted minutes), or in parallel to highlight an autoloading issues in your PR status checks.
The following line can run in any shell to perform the same job as the rspec snippet above:
rails r 'Zeitwerk::Loader.eager_load_all'
Here is an example of my CircleCI flow for a recently upgraded rails project. Notice how Zeitwerk failure prevented a ton of other jobs triggering, which would have used quite a lot of resources and failed much later.
This, of course, does not replace the need for an extensive test suite, but it can save you in the early days of prototype development where a typo or unused class can slip into the codebase when working at a fast pace.
Top comments (3)
I ran into a similar problem, and I ended up enabling eager loading when tests are running on CI:
Good shout! This is a great way for getting this behaviour without any CI changes at all.
The only downside to this is that it's hard to see what the actual issue is without going into the sea of red rspec logs. I prefer to have one CI job per specific thing that's being built/tested, but it's a bit more work to configure.
Configuring this in a chained workflow also means other jobs (like rspec, webpacker etc) can be prevented from even starting to execute, rather than each one being setup in parallel and all failing with the same error.
Thank you, this writing is really a life saver!