在生产环境中加载lib文件

问题描述 投票:0回答:13

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

现在我的生产服务器上总是出现错误,因为我在

application.rb
文件中使用自动加载功能加载所有 lib 文件。

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

目前,我已将

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

ruby-on-rails autoload ruby-on-rails-5
13个回答
177
投票

迁移到 Rails 5 后我的更改列表:

  1. lib
    目录放入
    app
    中,因为应用程序内的所有代码在开发中都是 autoloaded,在产品中是 eager returned,最重要的是在开发中是 autoreloaded,因此每次创建时都不必重新启动服务器变化。
  2. 删除
    require
    中指向您自己的类的任何
    lib
    语句,因为如果文件/目录命名正确,它们都会自动加载,并且如果您留下
    require
    语句,它可能会破坏自动重新加载。更多信息这里
  3. 在所有环境中设置
    config.eager_load = true
    ,以便在开发中热切地看到代码加载问题。
  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 }
    

117
投票

我只是使用

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

适用于开发和生产环境。

感谢Johan建议将

#{Rails.root}/lib
替换为
Rails.root.join('lib')


38
投票

出于线程安全的考虑,生产环境中禁用自动加载。感谢@Зелёный 提供的链接。

我按照

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


24
投票

在生产环境中自动加载被禁用一定是有原因的 默认。

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


13
投票

这允许自动重新加载库,并且也可以在生产环境中使用。

附注我改变了我的答案,现在它添加了两个 eager- 自动加载路径,无论环境如何,也允许在自定义环境中工作(如舞台)

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

9
投票

只需在 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')

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


5
投票

从某种意义上说,Rails 5 中有一个统一的方法来集中 eager 和 autoload 配置,同时在配置 eager load 时添加所需的 autoload 路径,否则将无法正常工作:

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

2
投票

对于像我一样遇到这个问题的人来说,仅仅在

app/
下放置一个目录是不够的。是的,您会自动加载,但不是必需的重新加载,这需要满足命名空间约定

此外,使用初始化程序加载旧的根级别

lib
将防止在开发过程中重新加载功能。


2
投票

我同意某些依赖项属于

lib
,有些可能属于
app/lib

我更喜欢加载我选择放入

lib
的所有环境的所有文件,因此我在需要捆绑包之后但在打开
config/application.rb
模块之前立即在
MyApplicationName
中执行此操作。

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

这不依赖于

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


1
投票

唯一对我有用的是在急切加载路径中添加嵌套的lib路径并在config.to_prepare块中添加require_dependency。

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

0
投票

将 lib 文件夹移至应用程序有助于解决问题,我的 Twitter api 无法在生产环境中运行。我有“未初始化的常量 TwitterApi”,并且我的 Twitter API 位于我的 lib 文件夹中。 我的 application.rb 中有

config.autoload_paths += Dir["#{Rails.root}/app/lib"]
,但在移动文件夹之前它不起作用。

这成功了


0
投票

config.autoload_lib(Rails 7.1+)

Rails 7.1开始,有一个新的配置方法,config.autoload_lib(ignore:)

它显着简化了

lib
文件夹的加载。

# config/application.rb
config.autoload_lib(ignore: ["assets", "tasks", "generators"])

来源:


-8
投票

总结 Lev 的答案:

mv lib app
足以让我所有的
lib
代码自动加载/自动重新加载。

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

© www.soinside.com 2019 - 2024. All rights reserved.