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

Jay*_*een 5 ruby-on-rails ruby-on-rails-6

我正在将 Rails 5.2.2 升级到现在具有Zeitwerk 的Rails 6.0.0 。

以前我已经扩展了核心 ruby​​ 类,如日期、时间、字符串、浮点数等,如本问题所述。使用初始化文件加载文件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)
Run Code Online (Sandbox Code Playgroud)

不幸的是,Zeitwerk 导致了一个错误,其中lib/core_ext/date.rbetc 抛出了一个已经定义的错误(当Rails.autoloaders.log!application.rb.CoreExt::Date

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

我在这里错过了什么?

lib/core_ext/date.rb

/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)
Run Code Online (Sandbox Code Playgroud)

我试过明确包装,CoreExt但这没有帮助。

module CoreExt
  class Date
    def to_sap
      strftime('%d.%m.%Y')
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

dpa*_*luy 6

我通过扩展核心功能并添加文件来具有相同的结构lib/extensions

我通过添加解决了这个问题

# config/application.rb
#
class Application < Rails::Application
  ...
  Rails.autoloaders.main.ignore(Rails.root.join('lib/extensions'))
end
Run Code Online (Sandbox Code Playgroud)

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

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


小智 4

正如https://github.com/fxn/zeitwerk#file-struct上所说

loader.push_dir(Rails.root.join("app/models"))
loader.push_dir(Rails.root.join("app/controllers"))
Run Code Online (Sandbox Code Playgroud)

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

自 Rails 3 起,lib 文件夹不属于自动加载路径。如果您想自动加载,@pixeltrix 是推荐的现代习惯用法。否则,lib 属于 $LOAD_PATH 并且您可以请求该目录中的文件。

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

loader.push_dir(Rails.root.join("app/models"))
loader.push_dir(Rails.root.join("app/controllers"))
Run Code Online (Sandbox Code Playgroud)

或者

# config/initializers/zeitwerk.rb

Rails.autoloaders.main.push_dir(Rails.root.join('lib'))
Run Code Online (Sandbox Code Playgroud)

然后CoreExt::Date就可以自动加载了。