如何在不破坏代码重新加载的情况下扩展 Rails 6/Zeitwerk 中的 gem 类?

nbr*_*ein 4 ruby-on-rails zeitwerk

当我使用 rails 6 / zeitwerk 时,如何扩展由 gem 定义的类?

我试过在初始化程序中使用它require首先加载类。我已经尝试在初始化程序中执行它,并且只是引用该类让自动加载首先加载它。

但是这两种方法都破坏了开发模式下的自动重新加载。

我试过将它放入lib/or app/,但这不起作用,因为这样该类永远不会从 gem 加载,因为我的新文件在加载顺序中更高。

还有一个类似的问题在这里,但一个专门询问如何在初始化做到这一点。我不在乎它是否在初始化程序中完成,我只想弄清楚如何以某种方式做到这一点。

做这样的事情的标准方法是什么?

我确实有一个似乎有效的讨厌的黑客,但我不喜欢它(更新:这也不起作用。重新加载仍然损坏):

the_gem_root = $LOAD_PATH.grep(/the_gem/).grep(/models/).first
require("#{the_gem_root}/the_gem/some_model")

class SomeModel

    def my_extension
        ...
    end

end
Run Code Online (Sandbox Code Playgroud)

Ale*_*xis 6

我知道已经晚了,但这真的很痛苦,有人会发现它很有帮助,在本示例中,我将使用位于应用程序上的模块文件夹,该文件夹将包含各种 gem 的自定义模块和猴子补丁。

# config/application.rb
...
module MyApp
  class Application < Rails::Application
    config.load_defaults(6.0)

    overrides = "#{Rails.root}/app/modules"

    Rails.autoloaders.main.ignore(overrides)

    config.to_prepare do
      Dir.glob("#{overrides}/**/*.rb").each do |override|
        load override
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

显然,这种模式称为覆盖模式,它将阻止 zeitwerk 自动加载您的覆盖,并且每个文件将在加载结束时手动加载。

  • 这需要被接受为正确答案。我一直在用头撞墙试图找到解决方案,Zeitwerk 在开发和生产中处理自动加载路径的方式不同,这并没有帮助我。由于到目前为止的惯例似乎是将 ruby​​ 核心库的扩展保留在 ${Rails.root}/lib/core_extensions 中,因此我相应地修改了上面的内容。 (2认同)