Rails 6 with Zeitwerk:如何扩展 Ruby 核心 类,如日期、时间、字符串等

Rails 6 with Zeitwerk: How to Extend Ruby Core Classes like Date, Time, String etc

我正在将 Rails 5.2.2 升级到 Rails 6.0.0,现在有 Zeitwerk

之前我已经扩展了核心 ruby 类,如日期、时间、字符串、浮点数等,如 this question 中所述。使用初始化文件加载 lib/core_ext/* 文件夹中的所有文件。启动 rails server 时,它现在会出错,堆栈跟踪的最后一行显示为:

/home/username/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/zeitwerk-2.1.10/lib/zeitwerk/loader.rb:351:in `const_get': uninitialized constant CoreExt::Date (NameError)

不幸的是,Zeitwerk 导致了一个错误,其中 lib/core_ext/date.rb 等抛出一个它已经被定义的错误(当在 application.rb 中使用 Rails.autoloaders.log! 时)。CoreExt::Date

我已经将文件直接移动到 initializers(以前我只有初始化程序目录,其中包含一个文件,该文件从 'lib/core_ext/* 文件夹加载每个文件)。这暂时解决了问题,但我想将 core_ext 文件夹和文件保留在原处。

我错过了什么?

lib/core_ext/date.rb

class Date
  def to_sap
    strftime('%d.%m.%Y')
  end
end

我曾尝试在 CoreExt 中显式换行,但这没有帮助。

module CoreExt
  class Date
    def to_sap
      strftime('%d.%m.%Y')
    end
  end
end

我通过扩展核心功能和在 lib/extensions

中添加文件来拥有相同的结构

我通过添加

解决了这个问题
# config/application.rb
#
class Application < Rails::Application
  ...
  Rails.autoloaders.main.ignore(Rails.root.join('lib/extensions'))
end

我继续像以前一样初始化扩展:

Dir[Rails.root.join('lib', 'extensions', '**', '*.rb')].each { |f| require f }

正如 https://github.com/fxn/zeitwerk#file-structure

上所说
loader.push_dir(Rails.root.join("app/models"))
loader.push_dir(Rails.root.join("app/controllers"))

Zeitwerk 作者:https://github.com/rails/rails/issues/37835#issuecomment-560563560

The lib folder does not belong to the autoload paths since Rails 3. @pixeltrix's is the recommended modern idiom if you want to autoload. Otherwise, lib belongs to $LOAD_PATH and you can require files in that directory.

我们可以调用push_dir加载lib子目录。我的解决方案:

# config/initializers/zeitwerk.rb

Rails.autoloaders.main.push_dir(Rails.root.join('lib'))

# config/application.rb

  ...
  config.autoload_paths += [
    Rails.root.join('lib')
  ]

然后CoreExt::Date可以自动加载