Rails 5: Load lib files in production

Ruby on-RailsAutoloadRuby on-Rails-5

Ruby on-Rails Problem Overview


I've upgraded one of my apps from Rails 4.2.6 to Rails 5.0.0. The Upgrade Guide says, that the Autoload feature is now disabled in production by default.

Now I always get an error on my production server since I load all lib files with autoload in the application.rb file.

module MyApp
	class Application < Rails::Application
		config.autoload_paths += %W( lib/ )
	end
end

For now, I've set the config.enable_dependency_loading to true but I wonder if there is a better solution to this. There must be a reason that Autoloading is disabled in production by default.

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

My list of changes after moving to Rails 5:

  1. Place lib dir into app because all code inside app is autoloaded in dev and eager loaded in prod and most importantly is autoreloaded in development so you don't have to restart server each time you make changes.

  2. Remove any require statements pointing to your own classes inside lib because they all are autoloaded anyway if their file/dir naming are correct, and if you leave require statements it can break autoreloading. More info here

  3. Set config.eager_load = true in all environments to see code loading problems eagerly in dev.

  4. Use Rails.application.eager_load! before playing with threads to avoid "circular dependency" errors.

  5. If you have any ruby/rails extensions then leave that code inside old lib directory and load them manually from initializer. This will ensure that extensions are loaded before your further logic that can depend on it:

    # config/initializers/extensions.rb
    Dir["#{Rails.root}/lib/ruby_ext/*.rb"].each { |file| require file }
    Dir["#{Rails.root}/lib/rails_ext/*.rb"].each { |file| require file }
    

Solution 2 - Ruby on-Rails

I just used config.eager_load_paths instead of config.autoload_paths like mention akostadinov on github comment: https://github.com/rails/rails/issues/13142#issuecomment-275492070

# config/application.rb
...
# config.autoload_paths << Rails.root.join('lib')
config.eager_load_paths << Rails.root.join('lib')

It works on development and production environment.

Thanks Johan for suggestion to replace #{Rails.root}/lib with Rails.root.join('lib')!

Solution 3 - Ruby on-Rails

Autoloading is disabled in the production environment because of thread safety. Thank you to @Зелёный for the link.

I solved this problem by storing the lib files in a lib folder in my app directory as recommended on Github. Every folder in the app folder gets loaded by Rails automatically.

Solution 4 - Ruby on-Rails

> There must be a reason that Autoloading is disabled in production by > default.

Here is a long discussion about this issue. https://github.com/rails/rails/issues/13142

Solution 5 - Ruby on-Rails

This allows to have lib autoreload, and works in production environment too.

P.S. I have changed my answer, now it adds to both eager- an autoload paths, regardless of environment, to allow work in custom environments too (like stage)

# config/initializers/load_lib.rb
...
config.eager_load_paths << Rails.root.join('lib')
config.autoload_paths << Rails.root.join('lib')
...

Solution 6 - Ruby on-Rails

Just change config.autoload_paths to config.eager_load_paths in config/application.rb file. Because in rails 5 autoloading is disabled for production environment by default. For more details please follow the link.

 #config.autoload_paths << "#{Rails.root}/lib"
  config.eager_load_paths << Rails.root.join('lib')

It works for both environment development and production.

Solution 7 - Ruby on-Rails

In some sense, here is a unified approach in Rails 5 to centralize eager and autoload configuration, in the same time it adds required autoload path whenever eager load is configured otherwise it won't be able to work correctly:

# config/application.rb
...
config.paths.add Rails.root.join('lib').to_s, eager_load: true

# as an example of autoload only config
config.paths.add Rails.root.join('domainpack').to_s, autoload: true
...

Solution 8 - Ruby on-Rails

For anyone struggled with this like me, it's not enough to just place a directory under app/. Yes, you'll get autoloading but not necessary reloading, which requires namespacing conventions to be fulfilled.

Also, using initializer for loading old root-level lib will prevent reloading feature during development.

Solution 9 - Ruby on-Rails

The only thing that worked for me is adding the nested lib path in eager load paths AND adding a require_dependency in a config.to_prepare block.

# application.rb
...
config.to_prepare do
  require_dependency("#{Rails.root}/lib/spree/core/product_filters.rb")
end

config.eager_load_paths << Rails.root.join('lib').join('spree').join('core')
...

Solution 10 - Ruby on-Rails

Moving the lib folder to app helped solve a problem, my Twitter api would not run in production. I had "uninitialized constant TwitterApi" and my Twitter API was in my lib folder. I had config.autoload_paths += Dir["#{Rails.root}/app/lib"] in my application.rb but it didn't work before moving the folder.

This did the trick

Solution 11 - Ruby on-Rails

I agree that some dependencies belong in lib and some may belong in app/lib.

I prefer to load all files I've chosen to put in lib for all environments, hence I do this in config/application.rb immediately after requiring the bundle but before opening the MyApplicationName module.

# load all ruby files in lib
Dir[File.expand_path('../../lib/**/*.rb', __FILE__)].each { |file| require file }

This doesn't depend on Rails.root (which isn't defined yet), and doesn't depend on eager loading (which may be off for an environment).

Solution 12 - Ruby on-Rails

to summarize Lev's answer: mv lib app was enough to have all my lib code autoloaded / auto-reloaded.

(rails 6.0.0beta3 but should work fine on rails 5.x too)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTobiasView Question on Stackoverflow
Solution 1 - Ruby on-RailsLev LukomskyView Answer on Stackoverflow
Solution 2 - Ruby on-RailsMichał ZalewskiView Answer on Stackoverflow
Solution 3 - Ruby on-RailsTobiasView Answer on Stackoverflow
Solution 4 - Ruby on-RailsPhilidorView Answer on Stackoverflow
Solution 5 - Ruby on-RailssrghmaView Answer on Stackoverflow
Solution 6 - Ruby on-RailsJitendra RathorView Answer on Stackoverflow
Solution 7 - Ruby on-RailspocheptsovView Answer on Stackoverflow
Solution 8 - Ruby on-RailsAbdullah BarrakView Answer on Stackoverflow
Solution 9 - Ruby on-RailsTashowsView Answer on Stackoverflow
Solution 10 - Ruby on-RailsLaurieView Answer on Stackoverflow
Solution 11 - Ruby on-RailseprothroView Answer on Stackoverflow
Solution 12 - Ruby on-RailslocalhostdotdevView Answer on Stackoverflow