Today I was making some improvements to a client's Rails codebase. This client has many services in the services/ folder of the Rails application, and a handful of them are related to a specific purpose. I wanted to put these services in their own folder so I can easily find them while I'm workig.

I created a new folder under services/ and tried to run the services the way I had been before, but it didn't work. I got an error about Uninitialized contant MyServiceName.

I read about autoloading in the Rails Guides and learned that by default, a Rails app makes all the code that's a direct child of any of the folders that are present when you bootstrap a new app available to any other code. So, code in services/service1.rb can see code in services/service_helper.rb without any configuration, and both can be ran from my Rails console. (bin/rails c).

When I moved code into a subfolder of services/, it's no longer a direct child of that folder and so doesn't get autoloaded. I can change that by adding subfolders of any folder that's there by default to the autoload paths in config/application.rb.

config.autoload_paths += Dir[Rails.root.join('app', 'services', '**/')]

After I added this line to the config, I had to exit my Rails console instance and re-enter it for my changes to take effect - reload! didn't pick up the config file changes.

But once I restarted my console, I was able to run my service without requireing anything special once more.

# Update 4-19-22

A coworker shared with me that if you namespace all your code in the subfolder using the name of the subfolder, you don't have to change the autoload paths and the code will get picked up automatically.

To namespace, either wrap everything in module FolderNameInCamelCase, or prefix your class names with FolderNameInCamelCase::.