简体   繁体   English

如何在 Rails 6/Zeitwerk 中扩展 gem class 而不破坏代码重新加载?

[英]How can I extend gem class in Rails 6/Zeitwerk without breaking code reloading?

How do I extend a class that is defined by a gem when I'm using rails 6 / zeitwerk?当我使用 rails 6 / zeitwerk 时,如何扩展由 gem 定义的 class?

I've tried doing it in an initializer using require to load up the class first.我已经尝试在初始化程序中使用require来首先加载 class 。 I've tried doing it in an initializer and just referencing the class to let autoloading load it up first.我尝试在初始化程序中执行此操作,并仅引用 class 以让自动加载首先加载它。

But both of those approaches break auto-reloading in development mode.但是这两种方法都破坏了开发模式下的自动重新加载。

I've tried putting it in lib/ or app/ , but that doesn't work because then the class never gets loaded from the gem, since my new file is higher up in the load order.我尝试将它放在lib/app/中,但这不起作用,因为 class 永远不会从 gem 中加载,因为我的新文件在加载顺序中更高。

There is a similar question here , but that one specifically asks how to do this in an initializer. 这里有一个类似的问题,但这个问题专门询问如何在初始化程序中执行此操作。 I don't care if it's done in an initializer or not, I just want to figure out how to do it some way.我不在乎它是否在初始化程序中完成,我只想弄清楚如何以某种方式做到这一点。

What is the standard way of doing something like this?做这样的事情的标准方法是什么?

I do have one nasty hack that seems to be working, but I don't like it (update: this doesn't work either. reloading is still broken):我确实有一个讨厌的黑客似乎正在工作,但我不喜欢它(更新:这也不起作用。重新加载仍然被破坏):

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

I know is late, but this was a real pain and someone could find it helpful, in this example I'll be using a modules folder located on app that will contain custom modules and monkey patches for various gems.我知道已经晚了,但这真的很痛苦,有人会觉得它很有帮助,在这个例子中,我将使用位于应用程序上的模块文件夹,其中包含用于各种宝石的自定义模块和猴子补丁。

# 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

Apparently this pattern is called the Override pattern, it will prevent the autoload of your overrides by zeitwerk and each file would be loaded manually at the end of the load.显然这种模式被称为 Override 模式,它将阻止 zeitwerk 自动加载您的覆盖,并且每个文件将在加载结束时手动加载。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM