更新情報
- 2014/03/03: 最初の版を公開
- 2020/11/18: Rails 5と6の情報を反映
Railsのルーティングを極める(後編)もご覧ください。
こんにちは、hachi8833です。今回も弊社CTOの馬場さんによる勉強会のスライドを元に記事を書きました。発表当時はRails3だったので、Rails4情報も追加しました。
Railsのルーティング(routes)を極めよう
2012/03: baba
Railsのルーティングはきわめて自由度が高い分、気を付けないとすぐカオスになってしまいます。Railsのルーティングのコツについて勉強していきましょう。Railsのルーティングはconfig/routes.rb
で設定します。
まずはrails routes
追記(2020/11/18):以前は
rake routes
コマンドでしたが、Rails 5や6ではrails routes
も使えるようになりましたので原則こちらで表記します(rake routes
も引き続き使えます)。
ルーティングを書く際にはrails routes
などでルーティングを確認しながら書く癖をつけましょう。ルーティングを作成するだけでなく、Railsのデバッグ時にも有用で、迷ったらとにかくrails routes
を実行してもいいくらいです。
rails routes
は実行のたびにRails環境を読み込むので、そのままでは遅いので有名です。以下のような方法で高速化しましょう。
- dev環境でRailsを起動中ならhttp://localhost:3000/rails/infoを参照する (Rails 4以降)
- pryとpry-rails gemがインストールされているなら、
rails console
を起動しておいてshow-routes
を実行 - spring gemがインストールされているなら
spring rails routes
とすれば2度目以降から高速になる
参考までに、Railsのルーティングを動的にビジュアル表示する方法を以下の記事にまとめました(graphvizをインストールする必要があります)。
改めて、RESTとは
RESTとは、Railsに敷かれているレールの一つである概念で、REpresentational State Transferの頭字語です。RESTの特徴は以下のとおりです。
- ステートレスであること
- すべてを「リソース」で表す
- リソースは名前を持つ
RESTに従っていることをRESTfulと呼んだりします。
RESTfulなURLの例
http://example.com/prefectures
http://example.com/users/1
RESTの反対はRPC
RESTのちょうど反対の概念がRPC(Remote Procedure Call)です。これはクエリ形式などと呼ばれることもあることからわかるように、?
の後ろに問い合わせを&
でつないで表現します。
RPC URLの例
http://example.com/index.php?action=prefecture_list&id=1
http://example.com/PrefectureList.aspx?id=1
Railsではresources
でルーティングを記述することで自動的にRESTfulなルーティングが生成されます。
以下はusersコントローラとproductsコントローラへのルーティングです。
resources :users
resources :products
その場合、対応するコントローラにもRESTfulなアクションが揃っている必要があります。rails generate scaffold
で生成した場合は自動的にRESTfulになります。
Railsでは、REST形式もRPC形式も両方扱うことができますが、RailsはRESTを「レール」として定めていますので、基本的には統一のためにRESTfulなルーティングの作成を心がけるようにしましょう。
ただし、RESTはあくまでポリシーであり万能ではないので、時にはRPC形式を一部に導入する方が素直に作れることもあります。
RESTメソッド
RESTとHTTPメソッドにはそれぞれ以下のような関係があります。なお、Rails 4 からはPUT
が非推奨となり、PATCH
が推奨されています。
RESTメソッド一覧
メソッド | 安全 | 冪等 |
---|---|---|
GET | ◯ | ◯ |
POST | × | × |
PATCH/PUT | × | ◯ |
DELETE | × | ◯ |
- 安全が×になっているのは、危険という意味ではなく、実行すると元のデータが更新されるという意味です。
- 同様に、安全が◯になっているのは、実行によって更新される心配がないという意味です。
-
冪等(べきとう: idempotent)は近年よく使われる用語で、「1回実行しても2回以上実行しても結果が変わらない」ことを指します(例: 1人殺しても3人殺しても死刑、は冪等です。1人殺せば犯罪者、1000人殺せば英雄、1億人殺せば神、だと冪等ではありません)。chefやvagrantなどのサーバーデプロイ用DSLではその目的のため冪等性が重視されます。
RESTfulなメソッドとURLの例
以下の表では、BPSという会社の所在地をGETメソッドとRESTfulなURLで表現した場合の例を示しています。
概念 | RESTfulなメソッドとURL |
---|---|
都道府県 | GET /prefectures |
東京都 | GET /prefectures/tokyo |
東京都市区町村一覧 | GET /prefectures/tokyo/cities |
東京都新宿区 | GET /prefectures/tokyo/cities/shinjuku |
東京都新宿区会社一覧 | GET /prefectures/tokyo/cities/shinjuku/companies |
東京都新宿区にあるBPSという会社 | GET /prefectures/tokyo/cities/shinjuku/companies/bps |
BPSという会社 | GET /companies/bps |
以下の表は、記事・ユーザ・コメントを表現した場合の例です。特に、IDが複数ある場合の表現方法にご注目ください。
概念 | RESTfulなメソッドとURL |
---|---|
記事一覧 | GET /articles |
記事(ID=1)、コメント一覧 | GET /articles/1/comments |
記事(ID=1)、コメント(ID=1) | GET /articles/1/comments/1 |
ユーザ(ID=1) | GET /users/1 |
ユーザ(ID=1)、パスワード | GET /users/1/password |
以下の表は、記事・ユーザ・コメントに対して操作を行なう場合の例です。Rails 4以降ではPUT
は非推奨になり、PATCH
が推奨されます。
概念 | RESTfulなメソッドとURL |
---|---|
記事を投稿する | POST /articles |
記事(ID=1)にコメントを投稿する | POST /articles/1/comments |
記事(ID=1)を更新する | PATCH /articles/1 |
記事(ID=1)のコメント(ID=1)を更新する | PATCH /articles/1/comments/1 |
記事(ID=1)を削除する | DELETE /articles/1 |
ユーザ(ID=1)のパスワードを更新する | PATCH /users/1/password |
(エラー) | POST /users/1/password |
ルーティングを綺麗に書くコツ
1. 原則は「RESTに従う」
原則として、RESTに従うようにしましょう。頑張ればresourceですべて書くことができます。ただし原理主義的に何が何でもresourceで書こうとすると、かえって見通しが悪くなることもありますので、ほどほどにしましょう。
resources :admin_menus, only:[ :index, :update ]
resources :menus, only:[ :index ]
resources :deadlines, except:[ :create, :destroy ]
2.以下の用語を理解する
- リソース
- HTTPメソッド(GET/POST/PATCH/PUT/DELETE)で操作する対象となるURLです。
- 名前付きルート
- 「パス_path」(ドメイン名より下のパスのみ)または「パス_url」(httpなどから始まるフルパス)という形式でURL形式を指定できます。たとえばContactページが/contactというパスにある場合、
contact_path
またはcontact_url
という名前付きルートで指定できます。名前付きルートは、パスヘルパーやURLヘルパーとも呼ばれます。これにより、コード上でURL構造を意識せずにパスを指定できます。
なお似ているけど違うのは「名前付きスコープ」と「名前付きパラメータ」です。 - ネストしたリソース
- ネストしたルーティングを記述することで、あるリソースを他のリソースの子にすることができます。
ネストしたリソースなどについて詳しくは、後編で解説します。
3. アルファベット順にソートする
これはメンテナンスのしやすさに通じます。
なお、ルーティングはファイルの上から順に有効になりますので、同じものを下に書いても効きません。
4. ルーティングファイルの分割を検討する
Railsアプリケーションが成長してルーティングが膨大になったら、config/routes.rbの分割を検討しましょう。
たとえば以下のようにconfig/application.rbに記載することで、config/routes.rbを分割してconfig/routes/以下のroutes_1.rbとroutes_2.rbに置くことができます。
config.paths["config/routes"] << "config/routes/routes_1.rb"
config.paths["config/routes"] << "config/routes/routes_2.rb"