问题
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.
回答1:
My list of changes after moving to Rails 5:
- Place
lib
dir intoapp
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. - Remove any
require
statements pointing to your own classes insidelib
because they all are autoloaded anyway if their file/dir naming are correct, and if you leaverequire
statements it can break autoreloading. More info here - Set
config.eager_load = true
in all environments to see code loading problems eagerly in dev. - Use
Rails.application.eager_load!
before playing with threads to avoid "circular dependency" errors. 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 }
回答2:
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.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')
!
回答3:
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.
回答4:
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
回答5:
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')
...
回答6:
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
...
回答7:
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.
回答8:
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
回答9:
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)
来源:https://stackoverflow.com/questions/38198668/rails-5-load-lib-files-in-production