routes.rbを部分ファイルに分割する方法(翻訳)
原文(How to split routes.rb into smaller parts? | Arkency Blog / February 27, 2015)です。英語の勉強にいいと思って、興味ある記事を日本語訳しています。間違いあれば教えてください。(#)は私の補足です。
Ruby on Railを使っているアプリケーションは、ルーティングエンジンとルーティングを定義するconfig/routes.rb
ファイルがあります。routes.rb
は開発していると非常に大きくなることがよくあります。1行追加するたびに、routes.rb
の保守が難しくなります。また、開発段階で特定のパスを探すことが、どんどん困難になります。現在、routes.rb
が約5000LOC(# lines of code)含まれているアプリケーションで作業しています。かなり多いですよね。解決策はとてもシンプルです。routes.rb
ファイルをいくつかの小さいファイルに分割することです。
ファイルの読み込み順
リクエストが来ると、routes.rb
ファイルは「上から下に」順番に処理されます。最初に適切にマッチしたルーティングが見つかると、リクエストは適切なコントローラーに転送されます。ファイル内で一致するパスが見つからない場合、Railsは404エラーになります。(# 分割された)ファイルの読み込む順が並び替わる可能性があるため、(# ファイルを分割した場合)名前空間の優先順位を定義できなければなりません。
解決策
次の例はroutes.rb
の一部です。
ActionController::Routing::Routes.draw do root to: "home#index" get "/about get "/login" => "application#login" namespace :api do #nested resources end namespace :admin do #nested resources end namespace :messages do #nested resources end namespace :orders do #nested resources end end
いくつかのデフォルト(# namespaceの指定がないルーティングのこと?)の名前空間(/home, /about, /loginのルーティングを指定した場合 )とその他 4つの名前空間があります。これらの名前空間は、私たちのアプリケーションは存在するコンテキスト(# 人間が分かりやすい形にってこと。adminは管理者だったり)をうまく定義します。よって、それらの namespace はファイルを分割するための最適な候補です。そのため、api.rb
、admin.rb
、messages.rb
, orders.rb
を作成しました。通常は、この分割ファイルをconfig/routes/
ディレクトリに置きます。次のステップは上記のファイルを読み込むことです。これを行うにはいくつかの方法があります。Rails 3 をベースにしたアプリケーションでは、アプリケーション設定からルートファイルを世も込むのが一般的な方法です。最終的にapplication.rb
に次の行を追加します。
config.paths["config/routes"] += Dir[Rails.root.join('config/routes/*.rb’)]
ファイルの読込み順を制御したい場合は、次のようにしてください。
config.paths["config/routes"] = %w( config/routes/messages.rb config/routes/orders.rb config/routes/admin.rb config/routes/api.rb config/routes.rb ).map { |relative_path| Rails.root.join(relative_path) }
ただし、Rails 4 以降では上記の行を追加すると例外が投げられます。Rails 4 はRails::Engineに[config / routes]
キーが提供されていません。Rails 3, 4 両方のバージョンで機能する別のオプションがあります。以下が別の解決方法です。
YourApplication::Application.routes.draw do def draw(routes_name) instance_eval(File.read(Rails.root.join("config/routes/#{routes_name}.rb"))) end draw :messages draw :orders draw :api draw :admin root to: "home#index" get "/about get "/login" => "application#login" end
パスの読み込みはActionDispatch::Routing
モジュールに新しいメソッドを追加することで可能になります。Rails 4 も最初は同様の解決策でしたが、削除されました。(# 前はRailsの機能として提供されていたが削除されてたということ。)
Revert "Allow loading external route files from the router" · rails/rails@5e7d6bb · GitHub
(# @dhh コメント「不透明になるのでRailsでは推奨したいものではないです。必要ならとても簡単なので自分で追加してください 」 )
結論
ファイルを分割することは、routes.rb
ファイルと日々の開発を改善するための非常に簡単な解決策です。本記事の解決策で、日々の開発が楽になります。
翻訳は以上です。こっからはワタシのひとり言
Railsがroutes.rbファイルの分割は不透明になるって言ってる、不透明ってなんだろう。
記述の重複(DRYじゃない)により小さく分割し共通化するのではなく、1ファイルの行数が増えたことにより分割することは、ただ全体像が追いづらい状態
になるだけってことか。さすがにroutes.rbが5000行になったことないけど、namespaceごとにファイル分けるのはすごくいい。