Why is mutating `autoload paths` discouraged?

The autoloading guide discusses the autoload_paths configuration setting and discourages its use:

The array of autoload paths can be extended by mutating config.autoload_paths , in config/application.rb , but nowadays this is discouraged.

Unfortunately there aren’t any reasons given and I’m finding I’d like to still use it to autoload things outside of the app directory.

Can anyone give some more insight on the reasoning behind this advice?

I’d say that is because Zeitwerk (Rails’ new autoloader) should load it all automatically already:

“Autoloading a constant no longer involves walking autoload paths looking for a relative match in the file system. Zeitwerk does one single pass and autoloads everything using absolute file names. In addition, that single pass descends into subdirectories lazily, only when the namespaces are used.”

from: Ruby on Rails — Zeitwerk integration in Rails 6 (Beta 2)

Though I’m not 100% sure it looks in all directories (not at my computer atm).

Thanks @mediafinger, I guess the question is, why is it discouraged to add other root paths to autoload_paths that are outside the /app directory? In my case I had a couple of files that I wanted to have autoloaded (and reloaded) but they didn’t really fit in the /app folder. Of course I can just go ahead and do it, but I wondered why it’s not really recommended :slight_smile:

Guess the eager_load_paths config value is prefered now that the autoload behavior changed.

@Spike we actually break up our monolith into small “packs” that sit at the project root. Each pack has their own set up app/* (autoloaded) directories. We inject these extra paths via Rails.application.paths['app'] << .... This as actually been working well. Only drawback is the paths that your app needs to “listen” to for changes is a lot more. Haven’t seen issues from that though.

Here’s the code: https://github.com/Gusto/stimpack/blob/main/lib/stimpack/integrations/rails.rb

That comment is inherited from the classic guide (commit). I imagine the reason is that pushing to autoload_paths does not push to eager_load_paths, and in the past you could not autoload in production after server boot due to limitations in classic mode.

This is no longer the case, and that guide needs to be revised for Rails 7. In Rails 7 classic mode is no longer available and the guide needs a pass.

It is true, however, that normally you want to push the directory also to the eager_load_paths to have it eager loaded, which is generally what you want. But, in any case, no problem adding your custom directories at all. Please consider that advice outdated.

1 Like

Thanks everyone :slight_smile: I was actually using eager_load_paths to bring these extra folders in pre-6.0 (due to that very issue of reloading).

I’m also using engines for the 20 or so components in my application. Works really well! And all of their app directories are autoloaded well.

Thanks for the clarification @fxn, that makes a lot of sense. That line in the docs did prompt me to reorganise things, but it’s probably for the best. Turns out most of it could be put in the app directory. The only ones that I had a hard time placing were Active Record association extensions. I made a directory off of app called extensions, but I really feel that they should be stored off of app/models like app/models/extensions but then they need to be needlessly prefixed with Extensions::. It’d probably be better to autoload that directory the same way that concerns is treated specially.

@Spike you can collapse that directory and avoid the namespace. Throw in config/application.rb or an initializer:

Rails.autoloaders.main.collapse("#{Rails.root}/app/models/extensions")

Ah, and your suggestion is also correct:

config.autoload_paths << "#{Rails.root}/app/models/extensions"

Zeitwerk will detect this is a subdirectory, same as concerns as you said.

Whatever feels better to you :).

Thanks @fxn, that actually makes a lot of sense. I ended up doing this:

Rails.autoloaders.main.collapse Rails.root.join('app/models/extensions')
Rails.autoloaders.main.collapse Rails.root.join('components/**/app/models/extensions')

Seems much tidier to me. I’ve always wondered why there’s never been an official filesystem space for AR extensions :slight_smile:

1 Like