更多内容请访问 rubyonrails.org:

1. 简介

本指南介绍 Rails 应用程序中的自动加载、重载和预加载。

在普通的 Ruby 程序中,你需要显式加载定义你想要使用的类和模块的文件。例如,以下控制器引用了 ApplicationControllerPost,你通常会为它们发出 require 调用

# DO NOT DO THIS.
require "application_controller"
require "post"
# DO NOT DO THIS.

class PostsController < ApplicationController
  def index
    @posts = Post.all
  end
end

但在 Rails 应用程序中并非如此,应用程序类和模块无需 require 调用即可随处可用

class PostsController < ApplicationController
  def index
    @posts = Post.all
  end
end

Rails 会根据需要为你自动加载它们。这得益于 Rails 为你设置的几个 Zeitwerk 加载器,它们提供了自动加载、重载和预加载功能。

另一方面,这些加载器不管理其他任何东西。特别是,它们不管理 Ruby 标准库、gem 依赖项、Rails 组件本身,甚至(默认情况下)应用程序的 lib 目录。这些代码必须像往常一样加载。

2. 项目结构

在 Rails 应用程序中,文件名必须与它们定义的常量匹配,目录充当命名空间。

例如,文件 app/helpers/users_helper.rb 应该定义 UsersHelper,文件 app/controllers/admin/payments_controller.rb 应该定义 Admin::PaymentsController

默认情况下,Rails 配置 Zeitwerk 以 String#camelize 来处理文件名。例如,它期望 app/controllers/users_controller.rb 定义常量 UsersController,因为这是 "users_controller".camelize 的返回值。

下面的《自定义词形变化》一节介绍了覆盖此默认设置的方法。

请查看 Zeitwerk 文档以获取更多详细信息。

3. config.autoload_paths

我们称应用程序目录的列表为“自动加载路径”,这些目录的内容将被自动加载并(可选地)重载。例如,app/models。这些目录表示根命名空间:Object

在 Zeitwerk 文档中,自动加载路径被称为“根目录”,但在本指南中,我们将继续使用“自动加载路径”。

在自动加载路径中,文件名必须与它们定义的常量匹配,如 此处 所述。

默认情况下,应用程序的自动加载路径由应用程序启动时存在的所有 app 子目录组成——除了 assetsjavascriptviews——以及它可能依赖的引擎的自动加载路径。

例如,如果 UsersHelperapp/helpers/users_helper.rb 中实现,则该模块是可自动加载的,你不需要(也不应该编写)它的 require 调用

$ bin/rails runner 'p UsersHelper'
UsersHelper

Rails 会自动将 app 下的自定义目录添加到自动加载路径。例如,如果你的应用程序有 app/presenters,你不需要配置任何东西来自动加载 presenter;它开箱即用。

可以通过在 config/application.rbconfig/environments/*.rb 中向 config.autoload_paths 推送来扩展默认的自动加载路径数组。例如

module MyApplication
  class Application < Rails::Application
    config.autoload_paths << "#{root}/extras"
  end
end

此外,引擎可以在引擎类的正文和它们自己的 config/environments/*.rb 中进行推送。

请不要修改 ActiveSupport::Dependencies.autoload_paths;更改自动加载路径的公共接口是 config.autoload_paths

在应用程序启动时,你不能在自动加载路径中自动加载代码。特别是在 config/initializers/*.rb 中直接自动加载。请查看下面的应用程序启动时的自动加载以了解有效的方法。

自动加载路径由 Rails.autoloaders.main 自动加载器管理。

4. config.autoload_lib(ignore:)

默认情况下,lib 目录不属于应用程序或引擎的自动加载路径。

配置方法 config.autoload_liblib 目录添加到 config.autoload_pathsconfig.eager_load_paths。它必须从 config/application.rbconfig/environments/*.rb 中调用,并且不适用于引擎。

通常,lib 包含不应由自动加载器管理的子目录。请在必需的 ignore 关键字参数中传入它们相对于 lib 的名称。例如

config.autoload_lib(ignore: %w(assets tasks))

为什么?虽然 assetstasks 与常规 Ruby 代码共享 lib 目录,但它们的内容不应被重载或预加载。

ignore 列表应包含所有不包含 .rb 扩展名的文件,或不应重载或预加载的 lib 子目录。例如,

config.autoload_lib(ignore: %w(assets tasks templates generators middleware))

config.autoload_lib 在 7.1 版本之前不可用,但只要应用程序使用 Zeitwerk,你仍然可以模拟它

# config/application.rb
module MyApp
  class Application < Rails::Application
    lib = root.join("lib")

    config.autoload_paths << lib
    config.eager_load_paths << lib

    Rails.autoloaders.main.ignore(
      lib.join("assets"),
      lib.join("tasks"),
      lib.join("generators")
    )

    # ...
  end
end

5. config.autoload_once_paths

你可能希望能够自动加载类和模块而无需重载它们。autoload_once_paths 配置存储可以自动加载但不会重载的代码。

默认情况下,此集合为空,但你可以通过向 config.autoload_once_paths 推送来扩展它。你可以在 config/application.rbconfig/environments/*.rb 中执行此操作。例如

module MyApplication
  class Application < Rails::Application
    config.autoload_once_paths << "#{root}/app/serializers"
  end
end

此外,引擎可以在引擎类的正文和它们自己的 config/environments/*.rb 中进行推送。

如果 app/serializers 被推送到 config.autoload_once_paths,Rails 将不再将其视为自动加载路径,尽管它是 app 下的自定义目录。此设置将覆盖该规则。

这对于缓存在重载后仍然存在的类和模块至关重要,例如 Rails 框架本身。

例如,Active Job 序列化器存储在 Active Job 内部

# config/initializers/custom_serializers.rb
Rails.application.config.active_job.custom_serializers << MoneySerializer

并且 Active Job 本身在重载时不会被重载,只有自动加载路径中的应用程序和引擎代码会被重载。

使 MoneySerializer 可重载会令人困惑,因为重载编辑过的版本对存储在 Active Job 中的类对象没有影响。实际上,如果 MoneySerializer 是可重载的,从 Rails 7 开始,这样的初始化器将引发 NameError

另一个用例是引擎装饰框架类

initializer "decorate ActionController::Base" do
  ActiveSupport.on_load(:action_controller_base) do
    include MyDecoration
  end
end

在那里,在初始化器运行时尚存储在 MyDecoration 中的模块对象成为 ActionController::Base 的祖先,重载 MyDecoration 毫无意义,它不会影响该祖先链。

来自一次自动加载路径的类和模块可以在 config/initializers 中自动加载。因此,通过这种配置,这可以工作

# config/initializers/custom_serializers.rb
Rails.application.config.active_job.custom_serializers << MoneySerializer

技术上讲,你可以在任何在 :bootstrap_hook 之后运行的初始化器中自动加载由 once 自动加载器管理的类和模块。

一次自动加载路径由 Rails.autoloaders.once 管理。

6. config.autoload_lib_once(ignore:)

方法 config.autoload_lib_once 类似于 config.autoload_lib,不同之处在于它将 lib 添加到 config.autoload_once_paths。它必须从 config/application.rbconfig/environments/*.rb 中调用,并且不适用于引擎。

通过调用 config.autoload_lib_oncelib 中的类和模块可以被自动加载,甚至可以从应用程序初始化器中自动加载,但不会被重载。

config.autoload_lib_once 在 7.1 之前不可用,但只要应用程序使用 Zeitwerk,你仍然可以模拟它

# config/application.rb
module MyApp
  class Application < Rails::Application
    lib = root.join("lib")

    config.autoload_once_paths << lib
    config.eager_load_paths << lib

    Rails.autoloaders.once.ignore(
      lib.join("assets"),
      lib.join("tasks"),
      lib.join("generators")
    )

    # ...
  end
end

7. 重载

如果自动加载路径中的应用程序文件发生变化,Rails 会自动重载类和模块。

更准确地说,如果 Web 服务器正在运行并且应用程序文件已被修改,Rails 会在处理下一个请求之前卸载由 main 自动加载器管理的所有自动加载常量。这样,在该请求期间使用的应用程序类或模块将再次自动加载,从而获取文件系统中的当前实现。

重载可以启用或禁用。控制此行为的设置是 config.enable_reloading,在 development 模式下默认为 true,在 production 模式下默认为 false。为了向后兼容,Rails 还支持 config.cache_classes,它等效于 !config.enable_reloading

Rails 默认使用事件文件监视器来检测文件更改。它也可以配置为通过遍历自动加载路径来检测文件更改。这由 config.file_watcher 设置控制。

在 Rails 控制台中,无论 config.enable_reloading 的值如何,都没有文件监视器处于活动状态。这是因为,通常,在控制台会话中间重载代码会令人困惑。与单个请求类似,你通常希望控制台会话由一组一致的、不变的应用程序类和模块提供服务。

但是,你可以通过执行 reload! 来强制在控制台中重载

irb(main):001:0> User.object_id
=> 70136277390120
irb(main):002:0> reload!
Reloading...
=> true
irb(main):003:0> User.object_id
=> 70136284426020

如你所见,重载后存储在 User 常量中的类对象是不同的。

7.1. 重载与陈旧对象

理解 Ruby 没有一种方法可以真正地在内存中重载类和模块,并让它在所有已经使用它们的地方都得到反映,这一点非常重要。技术上,“卸载” User 类意味着通过 Object.send(:remove_const, "User") 删除 User 常量。

例如,查看这个 Rails 控制台会话

irb> joe = User.new
irb> reload!
irb> alice = User.new
irb> joe.class == alice.class
=> false

joe 是原始 User 类的实例。当发生重载时,User 常量会评估为不同的、已重载的类。alice 是新加载的 User 的实例,但 joe 不是——他的类是陈旧的。你可以再次定义 joe,启动一个 IRB 子会话,或者只是启动一个新的控制台而不是调用 reload!

你可能遇到此陷阱的另一种情况是在未重载的位置子类化可重载类

# lib/vip_user.rb
class VipUser < User
end

如果 User 被重载,由于 VipUser 没有被重载,VipUser 的超类是原始的陈旧类对象。

底线是:不要缓存可重载的类或模块

8. 应用程序启动时的自动加载

在启动期间,应用程序可以从由 once 自动加载器管理的一次自动加载路径中进行自动加载。请查看上面的 config.autoload_once_paths 部分。

但是,你不能从由 main 自动加载器管理的自动加载路径中进行自动加载。这适用于 config/initializers 中的代码以及应用程序或引擎初始化器。

为什么?初始化器只在应用程序启动时运行一次。它们在重载时不会再次运行。如果初始化器使用了可重载的类或模块,那么对它们的编辑将不会反映在初始代码中,从而变得陈旧。因此,在初始化期间引用可重载常量是不允许的。

让我们看看应该怎么做。

8.1. 用例 1:启动时加载可重载代码

8.1.1. 在启动和每次重载时自动加载

假设 ApiGateway 是一个可重载类,你需要在应用程序启动时配置其端点

# config/initializers/api_gateway_setup.rb
ApiGateway.endpoint = "https://example.com" # NameError

初始化器不能引用可重载常量,你需要将其封装在 to_prepare 块中,该块在启动时运行,并在每次重载后运行

# config/initializers/api_gateway_setup.rb
Rails.application.config.to_prepare do
  ApiGateway.endpoint = "https://example.com" # CORRECT
end

由于历史原因,此回调可能会运行两次。它执行的代码必须是幂等的。

8.1.2. 仅在启动时自动加载

可重载类和模块也可以在 after_initialize 块中自动加载。这些块在启动时运行,但在重载时不会再次运行。在某些特殊情况下,这可能是你想要的。

预检是这种情况下的一个用例

# config/initializers/check_admin_presence.rb
Rails.application.config.after_initialize do
  unless Role.where(name: "admin").exists?
    abort "The admin role is not present, please seed the database."
  end
end

8.2. 用例 2:启动时加载保持缓存的代码

有些配置会接受一个类或模块对象,并将其存储在不会重载的位置。重要的是这些对象不可重载,因为编辑不会反映在那些缓存的陈旧对象中。

一个例子是中间件

config.middleware.use MyApp::Middleware::Foo

当你重载时,中间件栈不受影响,因此 MyApp::Middleware::Foo 可重载会令人困惑。其实现中的更改将无效。

另一个例子是 Active Job 序列化器

# config/initializers/custom_serializers.rb
Rails.application.config.active_job.custom_serializers << MoneySerializer

在初始化期间 MoneySerializer 评估的任何内容都会被推送到自定义序列化器中,并且该对象在重载时会保留在那里。

另一个例子是 railties 或引擎通过包含模块来装饰框架类。例如,turbo-rails 以这种方式装饰 ActiveRecord::Base

initializer "turbo.broadcastable" do
  ActiveSupport.on_load(:active_record) do
    include Turbo::Broadcastable
  end
end

这会将一个模块对象添加到 ActiveRecord::Base 的祖先链中。如果 Turbo::Broadcastable 被重载,其更改将无效,祖先链仍将保留原始模块。

推论:这些类或模块不可重载

组织这些文件的一种惯用方法是将它们放在 lib 目录中,并在需要时使用 require 加载它们。例如,如果应用程序在 lib/middleware 中有自定义中间件,则在配置它之前发出一个常规的 require 调用

require "middleware/my_middleware"
config.middleware.use MyMiddleware

此外,如果 lib 在自动加载路径中,请配置自动加载器以忽略该子目录

# config/application.rb
config.autoload_lib(ignore: %w(assets tasks ... middleware))

因为你是自己加载这些文件的。

如上所述,另一种选择是将定义它们的目录放在一次自动加载路径中并自动加载。请查看 关于 config.autoload_once_paths 的部分 以获取详细信息。

8.3. 用例 3:为引擎配置应用程序类

假设一个引擎使用可重载的应用程序类来建模用户,并为此设置了一个配置点

# config/initializers/my_engine.rb
MyEngine.configure do |config|
  config.user_model = User # NameError
end

为了与可重载的应用程序代码良好协作,引擎反而需要应用程序配置该类的名称

# config/initializers/my_engine.rb
MyEngine.configure do |config|
  config.user_model = "User" # OK
end

然后,在运行时,config.user_model.constantize 会为你提供当前的类对象。

9. 预加载

在类生产环境中,通常最好在应用程序启动时加载所有应用程序代码。预加载将所有内容加载到内存中,以便立即响应请求,并且它也支持 CoW(写时复制)

预加载由标志 config.eager_load 控制,除 production 环境外,在所有环境中默认禁用。当 Rake 任务执行时,config.eager_load 会被 config.rake_eager_load 覆盖,后者默认为 false。因此,默认情况下,在生产环境中 Rake 任务不会预加载应用程序。

文件预加载的顺序是未定义的。

在预加载期间,Rails 调用 Zeitwerk::Loader.eager_load_all。这确保了由 Zeitwerk 管理的所有 gem 依赖项也都被预加载。

10. 单表继承

单表继承与延迟加载配合不佳:Active Record 必须了解 STI 层次结构才能正常工作,但在延迟加载时,类恰好只在需要时加载!

为了解决这种根本性的不匹配,我们需要预加载 STI。有几种方法可以实现此目的,它们各有优缺点。让我们看看它们。

10.1. 选项 1:启用预加载

预加载 STI 最简单的方法是启用预加载,通过设置

config.eager_load = true

config/environments/development.rbconfig/environments/test.rb 中。

这很简单,但可能代价高昂,因为它在启动时和每次重载时都会预加载整个应用程序。不过,对于小型应用程序来说,这种权衡可能是值得的。

10.2. 选项 2:预加载折叠目录

将定义层次结构的文件存储在专用目录中,这在概念上也很有意义。该目录不代表命名空间,其唯一目的是将 STI 分组

app/models/shapes/shape.rb
app/models/shapes/circle.rb
app/models/shapes/square.rb
app/models/shapes/triangle.rb

在这个例子中,我们仍然希望 app/models/shapes/circle.rb 定义 Circle,而不是 Shapes::Circle。这可能是你个人偏好,为了保持简单,也避免了对现有代码库进行重构。Zeitwerk 的 折叠 功能允许我们这样做

# config/initializers/preload_stis.rb

shapes = "#{Rails.root}/app/models/shapes"
Rails.autoloaders.main.collapse(shapes) # Not a namespace.

unless Rails.application.config.eager_load
  Rails.application.config.to_prepare do
    Rails.autoloaders.main.eager_load_dir(shapes)
  end
end

在这个选项中,即使 STI 未使用,我们也会在启动和重载时预加载这几个文件。但是,除非你的应用程序有大量 STI,否则这不会产生任何可衡量的影响。

Zeitwerk::Loader#eager_load_dir 方法在 Zeitwerk 2.6.2 中添加。对于旧版本,你仍然可以列出 app/models/shapes 目录并对其内容调用 require_dependency

如果 STI 中添加、修改或删除了模型,重载会按预期工作。但是,如果向应用程序添加了新的独立 STI 层次结构,则需要编辑初始化器并重新启动服务器。

10.3. 选项 3:预加载常规目录

与上一个类似,但该目录旨在成为一个命名空间。也就是说,app/models/shapes/circle.rb 预计会定义 Shapes::Circle

对于这个选项,初始化器是相同的,只是没有配置折叠

# config/initializers/preload_stis.rb

unless Rails.application.config.eager_load
  Rails.application.config.to_prepare do
    Rails.autoloaders.main.eager_load_dir("#{Rails.root}/app/models/shapes")
  end
end

同样的权衡。

10.4. 选项 4:从数据库预加载类型

在这个选项中,我们不需要以任何方式组织文件,但我们会访问数据库

# config/initializers/preload_stis.rb

unless Rails.application.config.eager_load
  Rails.application.config.to_prepare do
    types = Shape.unscoped.select(:type).distinct.pluck(:type)
    types.compact.each(&:constantize)
  end
end

即使表中没有所有类型,STI 也能正常工作,但像 subclassesdescendants 这样的方法不会返回缺失的类型。

如果 STI 中添加、修改或删除了模型,重载会按预期工作。但是,如果向应用程序添加了新的独立 STI 层次结构,则需要编辑初始化器并重新启动服务器。

11. 自定义词形变化

默认情况下,Rails 使用 String#camelize 来知道给定文件或目录名应该定义哪个常量。例如,posts_controller.rb 应该定义 PostsController,因为这是 "posts_controller".camelize 返回的结果。

在某些情况下,某些特定文件或目录名可能不会像你希望的那样进行词形变化。例如,html_parser.rb 默认情况下应定义 HtmlParser。如果你更喜欢该类是 HTMLParser 怎么办?有几种方法可以自定义此行为。

最简单的方法是定义首字母缩写词

ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.acronym "HTML"
  inflect.acronym "SSL"
end

这样做会影响 Active Support 的全局词形变化。这在某些应用程序中可能没问题,但你也可以通过向默认的词形处理器传递一组覆盖项来独立于 Active Support 自定义单个基名的驼峰式命名

Rails.autoloaders.each do |autoloader|
  autoloader.inflector.inflect(
    "html_parser" => "HTMLParser",
    "ssl_error"   => "SSLError"
  )
end

然而,这种技术仍然依赖于 String#camelize,因为这是默认词形处理器用作备用的。如果你完全不想依赖 Active Support 的词形变化,并对词形变化拥有绝对控制权,请将词形处理器配置为 Zeitwerk::Inflector 的实例

Rails.autoloaders.each do |autoloader|
  autoloader.inflector = Zeitwerk::Inflector.new
  autoloader.inflector.inflect(
    "html_parser" => "HTMLParser",
    "ssl_error"   => "SSLError"
  )
end

没有全局配置可以影响所述实例;它们是确定性的。

你甚至可以定义一个自定义词形处理器以实现完全灵活性。请查看 Zeitwerk 文档以获取更多详细信息。

11.1. 词形变化自定义应放在何处?

如果应用程序不使用 once 自动加载器,上述代码片段可以放在 config/initializers 中。例如,Active Support 用例是 config/initializers/inflections.rb,其他用例是 config/initializers/zeitwerk.rb

使用 once 自动加载器的应用程序必须将此配置移动或加载到 config/application.rb 中的应用程序类主体中,因为 once 自动加载器在启动过程的早期使用词形处理器。

12. 自定义命名空间

如上所述,自动加载路径代表顶级命名空间:Object

例如,我们以 app/services 为例。此目录默认不生成,但如果它存在,Rails 会自动将其添加到自动加载路径。

默认情况下,文件 app/services/users/signup.rb 预计会定义 Users::Signup,但如果你希望整个子树都在 Services 命名空间下怎么办?那么,在默认设置下,可以通过创建子目录 app/services/services 来实现。

然而,根据你的喜好,这可能并不适合你。你可能更喜欢 app/services/users/signup.rb 简单地定义 Services::Users::Signup

Zeitwerk 支持 自定义根命名空间 来解决此用例,你可以自定义 main 自动加载器来实现此目的

# config/initializers/autoloading.rb

# The namespace has to exist.
#
# In this example we define the module on the spot. Could also be created
# elsewhere and its definition loaded here with an ordinary `require`. In
# any case, `push_dir` expects a class or module object.
module Services; end

Rails.autoloaders.main.push_dir("#{Rails.root}/app/services", namespace: Services)

Rails < 7.1 不支持此功能,但你仍然可以在同一文件中添加此附加代码并使其工作

# Additional code for applications running on Rails < 7.1.
app_services_dir = "#{Rails.root}/app/services" # has to be a string
ActiveSupport::Dependencies.autoload_paths.delete(app_services_dir)
Rails.application.config.watchable_dirs[app_services_dir] = [:rb]

once 自动加载器也支持自定义命名空间。但是,由于它在启动过程的早期设置,因此不能在应用程序初始化器中进行配置。相反,请将其放在 config/application.rb 中,例如。

13. 自动加载与引擎

引擎在父应用程序的上下文中运行,其代码由父应用程序自动加载、重载和预加载。如果应用程序在 zeitwerk 模式下运行,则引擎代码由 zeitwerk 模式加载。如果应用程序在 classic 模式下运行,则引擎代码由 classic 模式加载。

当 Rails 启动时,引擎目录被添加到自动加载路径中,从自动加载器的角度来看,没有区别。自动加载器的主要输入是自动加载路径,它们属于应用程序源树还是某些引擎源树是无关紧要的。

例如,此应用程序使用 Devise

$ bin/rails runner 'pp ActiveSupport::Dependencies.autoload_paths'
[".../app/controllers",
 ".../app/controllers/concerns",
 ".../app/helpers",
 ".../app/models",
 ".../app/models/concerns",
 ".../gems/devise-4.8.0/app/controllers",
 ".../gems/devise-4.8.0/app/helpers",
 ".../gems/devise-4.8.0/app/mailers"]

如果引擎控制其父应用程序的自动加载模式,则引擎可以照常编写。

但是,如果引擎支持 Rails 6 或 Rails 6.1 并且不控制其父应用程序,它必须准备好在 classiczeitwerk 模式下运行。需要考虑的事项

  1. 如果 classic 模式需要 require_dependency 调用以确保某个常量在某个时候被加载,请编写它。虽然 zeitwerk 不需要它,但它不会造成伤害,它在 zeitwerk 模式下也能工作。

  2. classic 模式下划线常量名(“User” -> “user.rb”),而 zeitwerk 模式驼峰式命名文件名(“user.rb” -> “User”)。它们在大多数情况下是相同的,但如果存在一连串连续大写字母(如“HTMLParser”),则不相同。最简单的兼容方式是避免此类名称。在这种情况下,选择“HtmlParser”。

  3. classic 模式下,文件 app/model/concerns/foo.rb 允许同时定义 FooConcerns::Foo。在 zeitwerk 模式下,只有一个选项:它必须定义 Foo。为了兼容,定义 Foo

14. 测试

14.1. 手动测试

zeitwerk:check 任务检查项目树是否遵循预期的命名约定,并且便于手动检查。例如,如果你正在从 classic 模式迁移到 zeitwerk 模式,或者如果你正在修复某些内容

$ bin/rails zeitwerk:check
Hold on, I am eager loading the application.
All is good!

根据应用程序配置,可能会有额外的输出,但你正在寻找的是最后的“一切正常!”。

14.2. 自动化测试

在测试套件中验证项目是否正确预加载是一个好习惯。

这涵盖了 Zeitwerk 命名合规性和其他可能的错误情况。请查看 测试 Rails 应用程序 指南中 关于测试预加载的部分

15. 故障排除

跟踪加载器活动最好的方法是检查它们的活动。

最简单的方法是在加载框架默认设置后,在 config/application.rb 中包含

Rails.autoloaders.log!

这会将跟踪信息打印到标准输出。

如果你更喜欢将日志记录到文件中,请改为配置此项

Rails.autoloaders.logger = Logger.new("#{Rails.root}/log/autoloading.log")

config/application.rb 执行时,Rails 日志记录器尚不可用。如果你更喜欢使用 Rails 日志记录器,请改为在初始化器中配置此设置

# config/initializers/log_autoloaders.rb
Rails.autoloaders.logger = Rails.logger

16. Rails.autoloaders

管理你的应用程序的 Zeitwerk 实例可在以下位置找到

Rails.autoloaders.main
Rails.autoloaders.once

谓词

Rails.autoloaders.zeitwerk_enabled?

在 Rails 7 应用程序中仍然可用,并返回 true



回到顶部