Rails 5: 在生产环境中加载 lib 文件

我已经把我的一个应用程序从 Rails 4.2.6升级到 Rails 5.0。升级指南表示,默认情况下,现在在生产环境中禁用了 Autoload 功能。

现在,我的生产服务器上总是出现错误,因为我在 application.rb文件中用 autoload 加载所有 lib 文件。

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

现在,我已经将 config.enable_dependency_loading设置为 true,但我想知道是否有一个更好的解决方案。在生产环境中默认禁用自动加载一定是有原因的。

98585 次浏览

禁用生产中的自动加载必须有原因 违约。

下面是关于这个问题的长篇讨论

由于线程安全,在生产环境中禁用自动加载。

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

在迁移到 Rails 5之后,我的更改列表如下:

  1. lib目录放入 app,因为应用程序中的所有代码在 dev 中是 自动装弹,在 prod 中是 满载而归,最重要的是在开发中的 自动重装的,所以每次更改时不必重新启动服务器。
  2. 删除指向 lib中自己类的任何 require语句,因为如果它们的文件/目录命名正确,它们都会被自动加载,如果留下 require语句,它可能会中断自动重载。更多信息 给你
  3. 在所有环境中设置 config.eager_load = true,以便在 dev 中查看代码加载问题。
  4. 在使用线程之前使用 Rails.application.eager_load!,以避免“循环依赖”错误。
  5. 如果您有任何 ruby/ails 扩展,那么将该代码保留在旧的 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 }
    

对于任何像我一样纠结于此的人来说,仅仅在 app/下放置一个目录是不够的。是的,你会得到自动加载,但不是必要的 重新加载,这需要满足命名空间约定

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

我只是用了 config.eager_load_paths而不是 config.autoload_paths,比如在 github 评论中提到了 akostadinov: 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')

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

感谢 约翰提出用 Rails.root.join('lib')代替 #{Rails.root}/lib的建议!

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

这个管用

这允许使用 lib 自动重载,并且也可以在生产环境中工作。

附注: 我已经改变了我的答案,现在它增加了两个渴望-一个自动加载路径,无论环境,以允许在自定义环境中的工作太(如阶段)

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

从某种意义上说,Rails 5采用了一种统一的方法来集中进行即时加载和自动加载配置,同时在配置即时加载时添加所需的自动加载路径,否则它将无法正常工作:

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

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

(Rails 6.0.0 beta 3,但也可以在 Rails 5.x 上正常工作)

只需在 config/application.rb 文件中将 Autoload _ path更改为 Ear _ load _ path即可。因为在 Rails5中,生产环境默认禁用自动加载。详情请参阅 链接

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

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

我同意有些依赖项属于 lib,有些可能属于 app/lib

我更喜欢加载我选择放入 lib中的所有文件,因此在需要绑定包之后,在打开 MyApplicationName模块之前,我会立即在 config/application.rb中加载这些文件。

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

这不依赖于 Rails.root(尚未定义) ,也不依赖于急切加载(对于环境可能关闭)。

对我来说,唯一有效的方法是在即时加载路径中添加嵌套的 lib 路径,并在 config.to _ ready 块中添加 need _ 倚赖项。

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