【问题标题】:Rails 5: Load lib files in productionRails 5:在生产中加载 lib 文件
【发布时间】:2016-11-07 00:13:35
【问题描述】:

我已将我的一个应用程序从 Rails 4.2.6 升级到 Rails 5.0.0。 Upgrade Guide 表示,自动加载功能现在在生产中默认禁用。

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

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

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

【问题讨论】:

  • 疯狂的事情,文档仍然告诉你做 auto_load。我很困惑新应用程序的生产环境中出了什么问题。自从我开始学习 Rails 5 以来,我没有阅读迁移指南。我提交了一个文档问题,希望能解决这个问题:github.com/rails/rails/issues/27268
  • 令人惊讶的是,我在lib 目录中有两个文件,一个文件在运行时很容易获得,但另一个必须手动要求:D
  • @Tobias 你最终得到了什么解决方案?
  • 这是关于正确的文件路径和类定义这对我来说在 Rails 5.2 中有用:文件路径:app/services/paylinx/paylinx_service.rb 类定义:module Paylinx class PaylinxService end end。我试过这些autoload_paths 的东西。对我不起作用。

标签: ruby-on-rails autoload ruby-on-rails-5


【解决方案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')
...

【讨论】:

  • 这对我也有用,而仅仅修改 eager_load_paths 没有。然而,在我看来,require_dependency 也可以从使用 join 方法中受益,即require_dependency(Rails.root.join('lib').join('spree').join('core').join('product_filters.rb'))
【解决方案2】:

我只是使用 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')

【讨论】:

  • 像魅力一样工作。我不喜欢这个语法,所以把它改成了config.eager_load_paths &lt;&lt; Rails.root.join('lib')
  • 对我来说这是最好的答案。我的项目从头开始在 Rails 5.2 上开始,文件夹 /lib 仍然在 /app 文件夹之外创建。我没有找到移动它的充分理由。
  • 是的,这行得通!似乎 Rails 开发人员真的很喜欢引起 lib 加载问题:D 直到下一次!
  • To Rails 5.2 使用 config.eager_load_paths += [Rails.root.join('lib')] 代替,因为 config.eager_load_paths 是一个冻结数组
  • @WilliamWongGaray config.eager_load_paths 在您尝试在初始化程序中修改它时是只读的。当您在application.rb 中添加路径时,它将同时使用这两种方法。
【解决方案3】:

我同意有些依赖项属于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(尚未定义),也不依赖于预加载(可能在某个环境中关闭)。

【讨论】:

    【解决方案4】:

    只需将 config/application.rb 文件中的 config.autoload_paths 更改为 config.eager_load_paths 即可。因为在 Rails 5 中,生产环境默认禁用自动加载。更多详情请关注link

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

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

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

        【解决方案6】:

        从某种意义上说,这是 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
        ...
        

        【讨论】:

          【解决方案7】:

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

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

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

          【讨论】:

          • 您能否详细说明为什么这可以解决问题?
          • @Stuart.Sklinar 这允许库自动重载,并且也可以在生产环境中工作。附言我已经改变了我的答案,现在它添加到两个渴望 - 一个自动加载路径,无论环境如何,也允许在自定义环境中工作(如舞台)
          • 你能扩展(在你的答案中)吗?仅代码答案并不能真正帮助任何人理解为什么应该“以这种方式”完成 - 我应该补充一点,我不是 Ruby 开发人员,只是帮助清理 SO。向“仅代码答案”添加一些评论会给它一些实际的上下文。
          • @Stuart.Sklinar 确定
          【解决方案8】:

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

          这成功了

          【讨论】:

            【解决方案9】:

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

            1. lib dir 放入app,因为应用程序内的所有代码在开发中自动加载,在生产中急切加载,最重要的是自动重新加载 em> 正在开发中,因此您不必每次进行更改时都重新启动服务器。
            2. 删除所有在lib 中指向您自己的类的require 语句,因为如果它们的文件/目录命名正确,它们都会自动加载,如果您留下require 语句,它可能会破坏自动重新加载。更多信息here
            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 }
              

            【讨论】:

            • 那么现在如何使用lib 文件夹呢?我的意思是将lib 目录移动到app 目录似乎有点像一种解决方法。
            • /app/lib/放置了一个文件/类并且它不是自动加载的。在 Rails 5.1 中测试,新项目
            • 值得注意的是,你需要停止spring。我将所有内容都移到了 app/lib/,然后浪费了一点时间想知道为什么我仍然无法从控制台使用我的类。弹簧停止ftw :)
            • 下面的行会去哪里Rails.application.eager_load!
            • 这可能有效,但不是最佳解决方案。文件夹结构也是语义的。 lib 中的事物与 app 目录中的事物具有不同的感知接近度。其他几个答案比这个更好。
            【解决方案10】:

            对于像我这样苦苦挣扎的人来说,仅仅在app/ 下放置一个目录是不够的。是的,您将获得自动加载,但不是必需的reloading, which requires namespacing conventions to be fulfilled

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

            【讨论】:

              【解决方案11】:

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

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

              【讨论】:

              • 如果你不想深入研究 Github 上冗长的讨论帖,你可以在这里找到精炼的解释:collectiveidea.com/blog/archives/2016/07/22/…
              • 我使用了config.eager_load_paths &lt;&lt; "#{Rails.root}/lib",IMO 最好遵循推荐的 Rails 应用程序结构。
              • rails 成员 github.com/rails/rails/issues/13142#issuecomment-275549669 建议将 lib 放入 app/lib
              • 这完全破坏了lib 的目的。我会等待温柔的爱或 DHH 加入。与此同时,我(个人)建议坚持@Lev Lukomsky 的回答。
              • @JoshBrody 我现在的看法是您根本不需要/lib 目录。第三方库大部分时间都是 gem,如果不是,应该创建一个 gem。对于其他文件,我在 /app 目录中创建特定文件夹。例如validators.
              【解决方案12】:

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

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

              【讨论】:

              • 本次讨论是我遇到的关于该主题的最佳信息来源,尽管阅读时间很长。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-10-06
              相关资源
              最近更新 更多