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.
