1 簡介
本指南說明 Rails 應用程式中的自動載入、重新載入和急切載入。
在一般的 Ruby 程式中,您會明確載入定義您要使用的類別和模組的檔案。例如,下列控制器參考了 ApplicationController
和 Post
,而您通常會對它們發出 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 標準函式庫、寶石相依性、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
之所有子目錄 ---除了 assets
、javascript
和 views
--- 加上它可能依賴的引擎的自動載入路徑。
例如,如果 UsersHelper
在 app/helpers/users_helper.rb
中實作,則此模組可自動載入,您不需要(也不應該撰寫)其 require
呼叫。
$ bin/rails runner 'p UsersHelper'
UsersHelper
Rails 會自動將 app
底下的自訂目錄新增至自動載入路徑。例如,如果您的應用程式有 app/presenters
,您不需要設定任何內容即可自動載入簡報者;它會立即運作。
預設自動載入路徑的陣列可透過在 config/application.rb
或 config/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_lib
將 lib
目錄新增至 config.autoload_paths
和 config.eager_load_paths
。它必須從 config/application.rb
或 config/environments/*.rb
呼叫,且不適用於引擎。
一般來說,lib
有不應由自動載入器管理的子目錄。請在必要的 ignore
關鍵字參數中傳遞它們相對於 lib
的名稱。例如
config.autoload_lib(ignore: %w(assets tasks))
為什麼?雖然 assets
和 tasks
與一般 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.rb
或 config/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.rb
或 config/environments/*.rb
呼叫,而且不適用於引擎。
透過呼叫 config.autoload_lib_once
,即使從應用程式初始化程式,也可以自動載入 lib
中的類別和模組,但不會重新載入。
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 $LOAD_PATH
預設會將自動載入路徑加入到 $LOAD_PATH
。不過,Zeitwerk 在內部使用絕對檔案名稱,而且應用程式不應該對可自動載入的檔案發出 require
呼叫,因此實際上不需要這些目錄。你可以使用這個標記來選擇退出
config.add_autoload_paths_to_load_path = false
由於查詢次數較少,這可能會稍微加快合法的 require
呼叫速度。此外,如果你的應用程式使用 Bootsnap,這可以讓函式庫免於建立不必要的索引,進而降低記憶體使用率。
這個標記不會影響 lib
目錄,它會永遠加入到 $LOAD_PATH
。
8 重新載入
如果自動載入路徑中的應用程式檔案變更,Rails 會自動重新載入類別和模組。
更精確地說,如果 Web 伺服器正在執行且應用程式檔案已修改,Rails 會在處理下一個要求之前卸載由 main
自動載入器管理的所有自動載入常數。這樣,在該要求期間使用的應用程式類別或模組將會再次自動載入,從而選取檔案系統中的目前實作。
可以啟用或停用重新載入。控制此行為的設定是 config.enable_reloading
,預設在 development
模式為 true
,在 production
模式預設為 false
。為了向後相容,Rails 也支援 config.cache_classes
,它等於 !config.enable_reloading
。
預設情況下,Rails 使用事件驅動的檔案監視器來偵測檔案變更。它可以改為透過瀏覽自動載入路徑來偵測檔案變更。這由 config.file_watcher
設定控制。
無論 config.enable_reloading
的值為何,在 Rails 主控台中都沒有啟用檔案監視器。這是因為,通常來說,在主控台工作階段中重新載入程式碼會令人困惑。類似於個別要求,你通常希望主控台工作階段由一組一致且不變的應用程式類別和模組來提供服務。
不過,你可以透過執行 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
常數中的類別物件已不同。
8.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
的超類別將是原始過時的類別物件。
重點是:不要快取可重新載入的類別或模組。
9 應用程式啟動時的自動載入
啟動時,應用程式可以從自動載入一次路徑自動載入,這些路徑由 once
自動載入器管理。請查看上面的 config.autoload_once_paths
區段。
不過,你無法從自動載入路徑自動載入,這些路徑由 main
自動載入器管理。這適用於 config/initializers
中的程式碼,以及應用程式或引擎的初始化程式。
為什麼?初始化程式只會在應用程式啟動時執行一次。它們不會在重新載入時再次執行。如果初始化程式使用了可重新載入的類別或模組,對它們的編輯將不會反映在那個初始程式碼中,因此會過時。因此,在初始化期間參照可重新載入的常數是不被允許的。
讓我們看看有哪些替代方案。
9.1 使用案例 1:在開機期間載入可重新載入的程式碼
9.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
基於歷史原因,此回呼可能會執行兩次。它執行的程式碼必須是冪等的。
9.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
9.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
在初始化期間評估為什麼,都會推送到自訂序列化器,而且該物件會在重新載入時保留在那裡。
另一個例子是透過包含模組來裝飾架構類別的軌道或引擎。例如,turbo-rails
就是以這種方式裝飾 ActiveRecord::Base
initializer "turbo.broadcastable" do
ActiveSupport.on_load(:active_record) do
include Turbo::Broadcastable
end
end
這會將模組物件新增到 ActiveRecord::Base
的祖先鏈中。如果 Turbo::Broadcastable
在重新載入時有變更,不會有任何影響,祖先鏈仍然會有原始的物件。
推論:那些類別或模組不能可重新載入。
在開機期間,最容易參照這些類別或模組的方法,是將它們定義在不屬於自動載入路徑的目錄中。例如,lib
是慣用的選擇。它預設不屬於自動載入路徑,但它屬於 $LOAD_PATH
。只需執行常規 require
即可載入它。
如上所述,另一個選項是在自動載入一次路徑和自動載入中定義它們的目錄。請查看 關於 config.autoload_once_paths 的章節 以取得詳細資料。
9.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
會提供目前的類別物件。
10 急切載入
在類似生產的環境中,通常最好在應用程式開機時載入所有應用程式程式碼。急切載入會將所有內容放入記憶體中,以便立即處理要求,而且它也 CoW- 友善。
急切載入由旗標 config.eager_load
控制,它在 production
以外的所有環境中預設停用。當執行 Rake 任務時,config.eager_load
會被 config.rake_eager_load
覆寫,預設為 false
。因此,預設情況下,在生產環境中,Rake 任務不會急切載入應用程式。
檔案的急切載入順序是未定義的。
在急切載入期間,Rails 會呼叫 Zeitwerk::Loader.eager_load_all
。這可確保由 Zeitwerk 管理的所有寶石依賴項也會急切載入。
11 單一表格繼承
單一表格繼承與延遲載入不搭:Active Record 必須了解 STI 階層才能正常運作,但延遲載入時,類別只會在需要時載入!
為了解決這個基本的不相容,我們需要預載入 STI。有幾個選項可以達成這個目標,各有不同的權衡。我們來看看它們。
11.1 選項 1:啟用熱切載入
預載入 STI 最簡單的方法是設定啟用熱切載入
config.eager_load = true
在 config/environments/development.rb
和 config/environments/test.rb
中。
這很簡單,但代價可能很高,因為它會在啟動和每次重新載入時熱切載入整個應用程式。不過,對於小型應用程式來說,這個權衡可能是值得的。
11.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 階層新增至應用程式,你將需要編輯初始化程式並重新啟動伺服器。
11.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
相同的權衡。
11.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 仍會正確運作,但 subclasses
或 descendants
等方法不會傳回遺失的類型。
如果從 STI 新增、修改或刪除模型,重新載入會如預期般運作。但是,如果將新的獨立 STI 階層新增至應用程式,你將需要編輯初始化程式並重新啟動伺服器。
12 自訂轉換
預設情況下,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 文件 以取得更多詳細資訊。
12.1 詞形變化自訂應放置何處?
如果應用程式未使用 once
自動載入器,上述程式片段可以放在 config/initializers
中。例如,Active Support 使用案例的 config/initializers/inflections.rb
,或其他使用案例的 config/initializers/zeitwerk.rb
。
使用 once
自動載入器的應用程式必須從 config/application.rb
中的應用程式類別主體移動或載入此組態,因為 once
自動載入器在開機程序的早期階段使用詞形變化器。
13 自訂命名空間
如上所述,自動載入路徑代表頂層命名空間: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
中,例如。
14 自動載入和引擎
引擎在父應用程式的脈絡中執行,其程式碼由父應用程式自動載入、重新載入和熱切載入。如果應用程式在 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,並且不控制其父應用程式,則它必須準備在 classic
或 zeitwerk
模式下執行。需要考慮的事項
如果
classic
模式需要require_dependency
呼叫來確保在某個時間點載入某些常數,請撰寫它。雖然zeitwerk
不需要它,但它不會造成傷害,它也會在zeitwerk
模式下執行。classic
模式底線表示常數名稱(「User」->「user.rb」),而zeitwerk
模式將檔案名稱駝峰化(「user.rb」->「User」)。在大多數情況下,它們是一致的,但如果存在連續大寫字母序列(如「HTMLParser」)則它們不一致。最簡單的相容方式是避免使用此類名稱。在這種情況下,請選擇「HtmlParser」。在
classic
模式中,檔案app/model/concerns/foo.rb
被允許定義Foo
和Concerns::Foo
。在zeitwerk
模式中,只有一個選項:它必須定義Foo
。為了相容,請定義Foo
。
15 測試
15.1 手動測試
zeitwerk:check
任務會檢查專案樹是否遵循預期的命名慣例,且適合用於手動檢查。例如,如果你要從 classic
模式遷移到 zeitwerk
模式,或如果你正在修正某些內容
$ bin/rails zeitwerk:check
Hold on, I am eager loading the application.
All is good!
可能會根據應用程式設定產生其他輸出,但最後的「一切都很好!」是你正在尋找的。
15.2 自動化測試
在測試套件中驗證專案是否正確地載入是良好的做法。
這涵蓋了 Zeitwerk 命名相容性和其他可能的錯誤狀況。請查看 測試 Rails 應用程式 指南中的 測試載入測試 部分。
16 疑難排解
追蹤載入器的活動是了解它們在做什麼的最佳方式。
最簡單的方法是包含
Rails.autoloaders.log!
在載入架構預設值後,在 config/application.rb
中。這會將追蹤列印到標準輸出。
如果你偏好將記錄寫入檔案,請改為設定這個
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
17 Rails.autoloaders
管理你的應用程式的 Zeitwerk 執行個體可以在
Rails.autoloaders.main
Rails.autoloaders.once
謂詞
Rails.autoloaders.zeitwerk_enabled?
在 Rails 7 應用程式中仍然可用,並傳回 true
。
回饋
我們鼓勵你協助改善本指南的品質。
如果你看到任何錯字或事實錯誤,請貢獻你的力量。要開始,你可以閱讀我們的 文件貢獻 部分。
你可能也會發現不完整的內容或未更新的內容。請務必為 main 新增任何遺漏的文件。請務必先查看 Edge Guides 以驗證問題是否已在 main 分支中修正。查看 Ruby on Rails 指南準則 以了解樣式和慣例。
如果您發現需要修復但無法自行修補的任何原因,請開啟問題。
最後但並非最不重要的一點是,歡迎在官方 Ruby on Rails 論壇上進行任何有關 Ruby on Rails 文件的討論。