如何使用Rails 6 / Zeitwerk在Rails初始化程序中预加载问题?

时间:2019-05-31 21:54:13

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

我正在使用一个初始化程序,该初始化程序通过将一些应用程序关注点包含到第三方库中来对应用程序进行一些猴子修补。基本上:

# config/initializers/my_initializer.rb

class SomeExternalLib
  include MyConcern1
  include MyConcern2
end

这在Rails 5.2.3中工作正常,但是在升级到Rails 6时我收到了以下弃用消息:

  

不建议使用警告:初始化会自动加载常量MyConcern1和MyConcern2。

     

不建议这样做。初始化期间将自动加载   在将来的Rails版本中会成为错误情况。

     

重新加载不会重新启动应用程序,因此在执行过程中执行了代码   初始化不会再次运行。因此,例如,如果您重新加载ApplicationHelper,   预期的更改将不会反映在该过时的Module对象中。

     

这些自动加载的常量已被卸载。

     

请查看“自动加载和重新加载常量”指南以获取解决方案。    (从/Users/myuser/code/myapp/config/environment.rb:7调用)

我的担忧在应用程序/控制器/问题/中。经过一番调查,我发现该路径没有被自动加载,但是我无法弄清楚如何使Zeitwerk(Rails 6的新自动加载器)动态地加载该路径。我尝试遵循here中所述的STI自动加载模式,但是没有运气。知道如何解决此弃用警告吗?

2 个答案:

答案 0 :(得分:15)

如@Glyoko的答案所述,对依赖项使用require可防止在初始化程序中自动加载。但是,如@Puhlze在他的评论中提到的那样,这样做会导致重新加载过程中出现问题。

我偶然发现了一种使用this post中的Rails.configuration.to_prepare的替代方法。

一个例子是:

# config/initializers/my_initializer.rb

Rails.configuration.to_prepare do
  class SomeExternalLib
    include MyConcern1
    include MyConcern2
  end
end

请注意,此操作在开发中的每个请求之前运行,但在渴望加载到生产中之前仅运行一次。

编辑:它似乎也可以重新加载。

答案 1 :(得分:1)

如果我更仔细地阅读错误消息会有所帮助:

  

在将来的Rails版本中,初始化期间的自动加载将成为错误条件。

有关更改的讨论是here,指南是here

简而言之,自动加载不应在初始化程序中完成,而这将被逐步淘汰。解决方案是:1)不要使用需要在初始值设定项中自动加载的东西(显然是首选),或2)明确要求初始值设定项具有依赖性。

所以我会这样做:

# config/initializers/my_initializer.rb

require 'my_concern1'
require 'my_concern2'

class SomeExternalLib
  include MyConcern1
  include MyConcern2
end