Altcademy - a Forbes magazine logo Best Coding Bootcamp 2023

What is Zeitwerk in Ruby on Rails?

Zeitwerk is a Ruby gem that provides a modern code loader for Ruby applications. It was introduced in Ruby on Rails 6 to solve a variety of issues related to the Rails autoloading system. In this blog post, we will explore what Zeitwerk is, why it was introduced, and how it works, with examples.

If you are new to programming or Ruby on Rails, don't worry! We will try to keep things simple and explain any jargon that we use.

What is a code loader?

Before diving into Zeitwerk, let's discuss what a code loader is and why it's important. In a programming language like Ruby, a code loader is responsible for locating, loading, and managing the source files of an application. It ensures that the correct file is loaded when a piece of code is executed, and it manages any dependencies between different files.

In simple terms, a code loader helps your application find and use the code you've written. Without a code loader, you would need to manually load each file in your application, which can quickly become unmanageable as your application grows.

What is autoloading?

Autoloading is a feature provided by code loaders that automatically loads the required source files when a piece of code is executed. This is a convenient feature that simplifies the management of source files in an application.

Imagine you have a large Ruby on Rails application with hundreds of classes spread across multiple files. Without autoloading, you would need to manually require each file whenever you want to use a class defined in it. This can be both tedious and error-prone.

With autoloading, you don't need to worry about manually requiring files. Instead, you can simply use the class, and the code loader will take care of finding and loading the appropriate file for you.

Why was Zeitwerk introduced?

Ruby on Rails has always provided an autoloading system, but it had some limitations that led to the introduction of Zeitwerk. Some of these limitations include:

Inconsistent file and class naming: In the Rails autoloading system, files and classes were expected to follow certain naming conventions. However, these conventions were not enforced, leading to inconsistencies and confusion.

Circular dependencies: The Rails autoloading system allowed for circular dependencies between files, which could cause issues in the application.

Runtime performance: The Rails autoloading system relied on const_missing to load files at runtime. This approach increased the complexity of the system and could lead to performance issues.

To address these limitations, Zeitwerk was introduced as the new autoloading system for Ruby on Rails. It enforces consistent file and class naming, eliminates circular dependencies, and improves runtime performance.

How does Zeitwerk work?

Now that we know what Zeitwerk is and why it was introduced, let's dive into how it works. Zeitwerk is built on the idea of a "strict naming convention" between files and classes. This means that the name of a file should directly correspond to the name of the class or module it defines.

For example, if you have a class called User, it should be defined in a file named user.rb. Similarly, if you have a module called Admin, it should be defined in a file named admin.rb.

Zeitwerk follows this strict naming convention to determine which file to load for a given class or module. When you reference a class or module in your code, Zeitwerk will look for a file with the corresponding name and load it for you.

Let's look at an example to see how Zeitwerk works in practice. Suppose you have a Rails application with the following file structure:

app/
  controllers/
    application_controller.rb
    users_controller.rb
  models/
    user.rb
config/
  application.rb

In this example, we have a User model defined in app/models/user.rb and a UsersController defined in app/controllers/users_controller.rb. With Zeitwerk, we can simply reference these classes in our code, and Zeitwerk will take care of loading the correct files for us:

# app/controllers/users_controller.rb
class UsersController < ApplicationController
  def index
    @users = User.all
  end
end

In this example, we didn't need to manually require the user.rb file in our users_controller.rb file. Zeitwerk took care of loading the User model for us when we referenced it in the UsersController class.

Zeitwerk and Rails

As mentioned earlier, Zeitwerk was introduced in Ruby on Rails 6 as the new autoloading system. To use Zeitwerk in your Rails application, you need to configure it in your config/application.rb file:

module YourApp
  class Application < Rails::Application
    config.load_defaults 6.0

    # ... any other configurations ...
  end
end

By setting config.load_defaults to 6.0, we are telling Rails to use Zeitwerk for autoloading. If you are using an older version of Rails, you can still use Zeitwerk by adding it to your Gemfile:

gem 'zeitwerk'

And then configuring it in your config/application.rb file:

module YourApp
  class Application < Rails::Application
    config.autoloader = :zeitwerk

    # ... any other configurations ...
  end
end

Benefits of Zeitwerk

Zeitwerk provides several benefits over the previous Rails autoloading system:

Consistent naming: By enforcing a strict naming convention between files and classes, Zeitwerk eliminates confusion and inconsistencies in your application's file structure.

No circular dependencies: Zeitwerk's strict naming convention eliminates the possibility of circular dependencies between files, leading to a more stable and predictable application.

Improved runtime performance: Zeitwerk's approach to autoloading improves runtime performance by avoiding the use of const_missing.

Simplified code: Since Zeitwerk takes care of loading files for you, you don't need to worry about manually requiring files in your application. This leads to cleaner and more maintainable code.

Common pitfalls and solutions

While Zeitwerk is a powerful and convenient tool, it's essential to be aware of some common pitfalls and how to solve them.

Incorrect file or class naming

As we mentioned earlier, Zeitwerk relies on a strict naming convention between files and classes. If you don't follow this convention, Zeitwerk may not be able to find and load the correct files for your classes.

To avoid this issue, always ensure that your file names match the names of the classes or modules they define. For example, if you have a class called User, it should be defined in a file named user.rb. If your class is namespaced, like Admin::User, it should be defined in a file named admin/user.rb.

Autoloading files outside of the Rails autoload paths

By default, Zeitwerk will only autoload files in the Rails autoload paths, which typically include the app/ and lib/ directories. If you have files outside of these directories that you want Zeitwerk to autoload, you need to add those directories to the Rails autoload paths.

You can do this in your config/application.rb file:

module YourApp
  class Application < Rails::Application
    # Add your custom directory to the autoload paths
    config.autoload_paths << Rails.root.join('your_custom_directory')

    # ... any other configurations ...
  end
end

Manually requiring files

In some cases, you may still need to manually require files in your application. This is typically necessary when you have files that don't follow the strict naming convention required by Zeitwerk, or when you need to load a file before Zeitwerk has a chance to autoload it.

To manually require a file, you can use the require or require_dependency methods:

require 'your_custom_file'
require_dependency 'your_custom_file'

Keep in mind that manually requiring files should be avoided whenever possible, as it can lead to confusion and inconsistencies in your application.

Conclusion

Zeitwerk is a powerful and modern code loader for Ruby on Rails applications that provides several benefits over the previous Rails autoloading system. By enforcing a strict naming convention between files and classes, Zeitwerk simplifies code management, eliminates circular dependencies, and improves runtime performance.

If you're starting a new Rails application or upgrading an existing one, consider using Zeitwerk to streamline your application's file management and autoloading. With its improved performance and simplified code, Zeitwerk is an excellent addition to any Ruby on Rails application.