Rails loads ActionCable via Zeitwerk

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!

Need help on your Ruby on Rails or React project?

Join Our Newsletter