Starting with Rails 6, Rails shipped with a new
and better way to autoload,
which delegates loading to the
Zeitwerk gem.
This is the zeitwerk
mode.
Before Rails 7, it was still possible to switch back to the classic
mode
which used an autoloader implemented in Active Support.
Rails now does not include this autoloader anymore.
Unfortunately, not all native Rails modules have been moved to the Zeitwerk yet.
Before
The classic autoloader has been extremely useful,
but had several issues that made autoloading a bit tricky
and confusing at times.
At a high level,
the classic mode loads files
by looking them up on Module.nesting
and Module.ancestors
.
This was a traversal, therefore, the first match would be loaded.
While this works fine most of the time the classic mode ran into some obscure failures.
Zeitwerk takes an entirely different approach
in auto-loading by registering constants to be autoloaded instead.
This removes the dependency load order.
Let’s look at a quick example,
# app/models/user.rb
class User < ApplicationRecord
end
# app/models/admin/user.rb
module Admin
class User < ApplicationRecord
end
end
# app/models/admin/user_manager.rb
module Admin
class UserManager
def self.all
User.all # Want to load all admin users
end
end
end
In the classic mode,
if Admin::UserManager
was loaded
before Admin::User
,
then calling User.all
would load from User
instead of Admin::User
.
However with Zeitwerk,
Rails will call Zeitwek#setup
.
This method takes care of setting up the autoloaders
for all of the known autoload_paths
.
The above example will look something like this,
autoload :User, Rails.root.join('app/models/user.rb')
autoload :Admin::User, Rails.root.join('app/models/admin/user.rb')
autoload :Admin::UserManager, Rails.root.join('app/models/admin/user_manager.rb')
Back to ActionCable! Prior to this change,
one had to specifically autoload all dependencies
of ActionCable so as to not run into any const_missing
error callbacks.
# actioncable/lib/action_cable.rb
autoload :Server
autoload :Connection
autoload :Channel
autoload :RemoteConnections
autoload :SubscriptionAdapter
autoload :TestHelper
autoload :TestCase
After
Thanks to this PR, much of this ‘bureaucratic’ code can now be removed!