【Rails】Zeitwerkについて調べたこと
Rails6から導入されたZeitwerkとはなんだろう
普段何気なく目にするけどよくわからない。。ということで改めて調べてみて知ったことを自分用にまとめた記事になります。
なぜRailsではrequireなしにファイルを読み込んでくれるのか
他の言語などにおいて、他のファイルを読み込むとなればimportするなどして、明示的に読み込む必要があるはずですが、Railsではそれをよしなにやってくれます。
Railsガイドによるとこう書かれています。
通常のRailsアプリケーションでrequire呼び出しを行うのは、libディレクトリにあるものや、Ruby標準ライブラリ、Ruby gemなどを読み込むときだけです。アプリケーションのクラスやモジュールはどこででも利用できます。
なぜでしょうか?
ひとことで言うならZeitwerkという仕組みがRailsには組み込まれているからなのです。
Zeitwerkとは
オートロードの仕組みです。
オートロードとは、命名規則にのっとったファイルを自動で読み込むという意味だそうです。
例えば、下記のように(A)のファイル名にもとづいて(B)の定数を読み込もうとする一方で、(B)の定数がどこかで使用されたときには(A)のファイルを読み込もうとするみたいなことを自動でやってくれています。
(A)app/controller/admins/items_controller.rb -> (B)Admins::ItemsController
もしもファイル名と異なる命名規則のモジュール名, クラス名が定義されていた場合はuninitialized constant
エラーなど発生し、うまく読み込まれずにエラーになり死んでしまいます。
オートロードが見ているパスの確認方法
じゃあ、Zeitwerkは今どのファイルを自動で読み込んでくれているか?
Railsでは便利な確認方法があり、次のコマンドをたたくと簡単に確認することができます。
$ rails r 'puts ActiveSupport::Dependencies.autoload_paths'
Running via Spring preloader in process 18451
/Users/murakami/HOGE/lib
/Users/murakami/HOGE/app/channels
/Users/murakami/HOGE/app/commands
/Users/murakami/HOGE/app/controllers
/Users/murakami/HOGE/app/errors
/Users/murakami/HOGE/app/forms
...
これでZeitwerkが自動で読み込みしてくれているパスの一覧が出力されて、Zeitwekがきちんと動いていることを確認することができます。
Zeitwekの設定方法
Rails6からは、下記のように記載があるだけで、デフォルトでZeitwerkを使用する設定になっています。
(config/application.rb)
config.load_defaults 6.0
以前のconst_missingを使用するには下記のように設定する必要があるようです。
(config/application.rb)
config.load_defaults 6.0
config.autoloader = :classic # クラシックモードを明示的に指定する
定数の推測をカスタマイズしたくなったら
ファイル名はapp/controllers/api_controller.rb
だけど、クラス名はAPIController
(APIを全て大文字)で意地でも定義したい! みたいなときもあると思います。
そんなときは下記ファイルに設定してやれば解決できます。
(config/initializers/zeitwerk.rb)
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.acronym "API"
end
他にもファイル名と異なるクラス名, モジュール名を設定したりできるみたいです。
下記の記事がたいへん参考になりました。
おわり
以前使用されていたconst_missingの仕組みを使用したオートロードの仕組みには、
処理順序により発生する不具合があったりして、直感的にエラーに気づきにくいということがあったということらしいですが、このへんの不便さというものを実感せずにここまできていたため「うわーめっちゃ便利になった!」という感覚はないのですが、そのような改善があったのだなーということはなんとなく覚えておこうと思いました。
Discussion