アプリケーション起動時にModelやControllerをごにょごにょするgemを開発していて気付いたことをメモ。
本記事は、ActiveRecordのeager_load
とはまた別の話なので注意。
eager load について
説明できる自信がないので、Railsの公式ドキュメントの説明に預けます。
config.eager_loadをtrueにすると、config.eager_load_namespacesに登録された事前一括読み込み(eager loading)用の名前空間をすべて読み込みます。ここにはアプリケーション、エンジン、Railsフレームワークを含むあらゆる登録済み名前空間が含まれます。
Railsのapp以下にあるクラス(ModelやController)をブート時に全て読み込む....といった感じでしょうか。
このconfig.eager_load
は通常、Railsの環境別にconfig/environments/xxxxxxxx.rb
で設定されています。(rails newした時にそうなっているはず)
SampleApp::Application.configure do
#...(略)...
# Do not eager load code on boot.
config.eager_load = false
#...(略)...
end
eager load をしない場合の挙動
Railsアプリケーションで、config.eager_load = false
になっていると、そのクラスが存在するか?(定数が存在するか?)を確認しようとしても、クラスにアクセスする前ならばfalse
が返ってきます。
コードを実行してみると、以下のような感じです。
irb(main):001:0> Object.const_defined?('User')
=> false
irb(main):002:0> Object.const_defined?('UsersController')
=> false
irb(main):003:0> User
=> User(id: integer, name: string, email: string, created_at: datetime, updated_at: datetime, password_digest: string, remember_token: string, admin: boolean)
irb(main):004:0> Object.const_defined?('User')
=> true
irb(main):005:0> UsersController
=> UsersController
irb(main):006:0> Object.const_defined?('UsersController')
=> true
eager load をする場合の挙動
config.eager_load = true
にしている場合です。
以下の通り、クラスにアクセスする前から、クラスの存在確認(定数定義の確認)をできるようになっています。
irb(main):001:0> Object.const_defined?('User')
=> true
irb(main):002:0> Object.const_defined?('UsersController')
=> true
eager_load! で強制的に読み込ませることもできる
ここまで述べてきた通り、config.eager_load
の値をtrueにすることで、Railsアプリケーション起動直後からクラスの存在確認をできるようになります。
が、どうしても、config.eager_load
の値によらず、クラスの存在確認をできるようにしたい場合、どうすればよいのでしょうか?
そこで登場するのが、Rails.application.eager_load!
というメソッドです。
このメソッドは、config.eager_load = true
の時と同じロード処理をその場で実行してくれます。
(それなりの規模のアプリケーションだと実行に時間がかかるかと思います)
動かしてみると、こんな感じです。
irb(main):001:0> Rails.application.eager_load!
=> ["/Users/ym/works/sample_app/app/assets", "/Users/ym/works/sample_app/app/controllers", "/Users/ym/works/sample_app/app/helpers", "/Users/ym/works/sample_app/app/mailers", "/Users/ym/works/sample_app/app/models", "/Users/ym/works/sample_app/app/controllers/concerns", "/Users/ym/works/sample_app/app/models/concerns"]
irb(main):002:0> Object.const_defined?('User')
=> true
irb(main):003:0> Object.const_defined?('UsersController')
=> true
通常は使わない方法かと思いますが、gem側で強制的にクラス存在確認を有効にしたい時など、どうしても必要になる時があるかもしれません。