Ruby-on-rails Rails 5:在生产中加载 lib 文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38198668/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 00:26:14  来源:igfitidea点击:

Rails 5: Load lib files in production

ruby-on-railsautoloadruby-on-rails-5

提问by Tobias

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

我已将我的一个应用程序从 Rails 4.2.6 升级到 Rails 5.0.0。该升级指南说,是自动加载功能在生产中默认情况下禁用现在。

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

现在我总是在我的生产服务器上收到错误,因为我在application.rb文件中加载了所有带有自动加载功能的 lib文件。

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

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

现在,我已经设置为config.enable_dependency_loadingtrue但我想知道是否有更好的解决方案。默认情况下在生产中禁用自动加载肯定是有原因的。

采纳答案by Tobias

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 libfolder in my appdirectory as recommended on Github. Every folder in the appfolder gets loaded by Rails automatically.

我按照Github 上的建议将 lib 文件存储lib在我的app目录中的文件夹中,从而解决了这个问题。Rails 会自动加载文件夹中的每个文件夹。app

回答by Lev Lukomsky

My list of changes after moving to Rails 5:

移至 Rails 5 后我的更改列表:

  1. Place libdir into appbecause all code inside app is autoloadedin dev and eager loadedin prod and most importantly is autoreloadedin development so you don't have to restart server each time you make changes.
  2. Remove any requirestatements pointing to your own classes inside libbecause they all are autoloaded anyway if their file/dir naming are correct, and if you leave requirestatements it can break autoreloading. More info here
  3. Set config.eager_load = truein 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 libdirectory 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 }
    
  1. libdir 放入,app因为应用程序中的所有代码在开发中自动加载并在生产中预先加载,最重要的是在开发中自动重新加载,因此每次进行更改时都不必重新启动服务器。
  2. 删除任何require指向内部类的语句,lib因为如果它们的文件/目录命名正确,它们都会自动加载,并且如果你离开require语句,它可能会破坏自动重新加载。更多信息在这里
  3. config.eager_load = true在所有环境中设置以在 dev 中急切地查看代码加载问题。
  4. 使用Rails.application.eager_load!播放与线程之前避免“循环依赖”的错误。
  5. 如果您有任何 ruby​​/rails 扩展,则将该代码保留在旧lib目录中并从初始化程序手动加载它们。这将确保在可以依赖它的进一步逻辑之前加载扩展:

    # 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 }
    

回答by Micha? Zalewski

I just used config.eager_load_pathsinstead of config.autoload_pathslike mention akostadinov on github comment: https://github.com/rails/rails/issues/13142#issuecomment-275492070

我只是使用config.eager_load_paths而不是config.autoload_paths在 github 评论中提及 akostadinov: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 Johanfor suggestion to replace #{Rails.root}/libwith Rails.root.join('lib')!

感谢Johan建议替换#{Rails.root}/libRails.root.join('lib')

回答by Зелёный

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

这是关于这个问题的长时间讨论。https://github.com/rails/rails/issues/13142

回答by srghma

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

这允许 lib autoreload,并且也可以在生产环境中使用。

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)

PS我已经改变了我的答案,现在它增加了两个急切的自动加载路径,无论环境如何,也允许在自定义环境中工作(如舞台)

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

回答by pocheptsov

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:

从某种意义上说,这是 Rails 5 中统一的方法来集中 Eager 和 Autoload 配置,同时它会在配置 Eager 加载时添加所需的自动加载路径,否则将无法正常工作:

# 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
...

回答by Jitendra Rathor

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

只需将config/application.rb 文件中的config.autoload_paths更改为config.eager_load_paths 即可。因为在 rails 5 中,生产环境默认禁用自动加载。欲了解更多详情,请点击链接

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

It works for both environment development and production.

它适用于环境开发和生产。

回答by Abdullah Barrak

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.

对于像我这样在这方面苦苦挣扎的人来说,仅仅在app/. 是的,您将获得自动加载,但不需要重新加载,这需要满足命名空间约定

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

此外,使用初始化程序加载旧的根级别lib将防止在开发过程中重新加载功能。

回答by Laurie

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.

将 lib 文件夹移动到 app 有助于解决一个问题,我的 Twitter api 无法在生产中运行。我有“未初始化的常量 TwitterApi”,我的 Twitter API 在我的 lib 文件夹中。我config.autoload_paths += Dir["#{Rails.root}/app/lib"]在我的 application.rb 中有,但在移动文件夹之前它不起作用。

This did the trick

这成功了

回答by localhostdotdev

to summarize Lev's answer: mv lib appwas enough to have all my libcode autoloaded / auto-reloaded.

总结列夫的回答:mv lib app足以让我所有的lib代码自动加载/自动重新加载。

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

(rails 6.0.0beta3 但在 rails 5.x 上也应该可以正常工作)