Rails 7.1 Improves Support for Custom Namespaces

A namespace is a way to group related functionality together in a modular way. Rails 7 has improved the support for the custom namespace, now there is a better way of adding the custom namespace to application components while autoloading.

Rails by default autoloads all the subdirectories in the app folder except assets, views, and javascript.

Even if there is a custom directory inside the app, for example, app/services, we don’t need to configure anything to autoload it, Rails does it automatically.

In a Rails application, file names have to match the constants they define, with directories acting as namespaces. For example, the file app/services/users/signup.rb has to define the constant like Users::Signup.

But what if we would like all our services in app/services under Services namespace, it means that we would want to define a constant like Services::Users::Signup.

One way to accomplish this is to create a subdirectory like app/services/services and then we can put all our services under the services namespace.

But this doesn’t feel right, there should be a way to define file app/services/users/signup.rb constant like Services::Users::Signup

Before

Now there are two modes of autoloading files in Rails, one is the classic mode and the other is zeitwerk mode.

Classic

In classic mode we can define constant in both ways for a file app/services/users/signup.rb. It means that Services::Users::Signup and Users::Signup are valid constant names. But it creates ambiguity.

Zeitwerk

In zeitwerk mode we can only define Users::Signup but there is a workaround. Zeitwerk supports custom root namespaces and we can customize main autoloader.

# config/initializers/autoloading.rb

module Services; end

Rails.autoloaders.main.push_dir("#{Rails.root}/app/services", Services)

ActiveSupport::Dependencies.autoload_paths("#{Rails.root}/app/services")

In the above code, we created a Services namespace, we can create it like this or we can create it elsewhere and then require it here.

Next, we used the main autoloader to do the task. The push_dir method takes a module or class object as the second argument.

Applications running on Rails < 7.1 have to additionally delete the directory app/services from ActiveSupport::Dependencies.autoload_paths.

After

Now after this patch, we can add the custom namespace Services without creating a subdirectory like app/services/services.

We just have to customize the main autoloader like below and that is it.

# config/initializers/autoloading.rb

module Services; end

Rails.autoloaders.main.push_dir("#{Rails.root}/app/services", Services)

There is no need to delete app/services from ActiveSupport::Dependencies.autoload_paths. For more information about this patch, please go through this PR.

Need help on your Ruby on Rails or React project?

Join Our Newsletter