Railsのルーティングを極める(後編)もご覧ください。
こんにちは、hachi8833です。今回も弊社CTOの馬場さんによる勉強会のスライドを元に記事を書きました。執筆当時はRails3だったので、Rails4情報も追加しました。
Railsのルーティング(routes)を極めよう
2012/03
baba
Railsのルーティングはきわめて自由度が高い分、気を付けないとすぐカオスになってしまいます。Railsのルーティングのコツについて勉強していきましょう。Railsのルーティングはconfig/routes.rb
で設定します。
とにかくrake routes
追記: 現在は
rake
コマンドがrails
コマンドに置き換えられつつあるので、rails routes
を使うのがよいでしょう。
ルーティングを書く際にはrake routes
を実行する癖をつけましょう。ルーティングを作成するだけでなく、Railsのデバッグ時にも有用で、迷ったらとにかくrake routes
を実行してもいいくらいです。
rake routes
は実行のたびにRails環境を読み込むので、そのままでは遅いので有名です。以下のような方法で高速化しましょう。
- pryとpry-rails gemがインストールされているなら、
rails console
を起動しておいてshow-routes
を実行 - spring gemがインストールされているなら
spring rake routes
とすれば2度目以降から高速になる - dev環境が起動中ならhttp://localhost:3000/rails/infoを参照する (Rails 4)
改めて、RESTとは
RESTとは、Railsに敷かれているレールの一つである概念で、REpresentational State Transferの頭字語です。その特徴は:
- ステートレスであること
- すべてを「リソース」で表す
- リソースは名前を持つ
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 http://example.com/xmlrpc
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ではその目的のため冪等性が重視されます。
以下の表では、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 |
ルーティングを綺麗に書くコツ
RESTに従う
原則として、RESTに従うようにしましょう。頑張ればresourceですべて書くことができます。が、原理主義的にがんばるとかえって見通しが悪くなることもありますのでほどほどにしましょう。
resources :admin_menus, only:[ :index, :update ]
resources :menus, only:[ :index ]
resources :deadlines, except:[ :create, :destroy ]
以下の名前を理解する
- リソース
- HTTPメソッド(GET/POST/PATCH/PUT/DELETE)で操作する対象となるURLです。
- 名前付きルート
- 「パス_path」(ドメイン名より下のパスのみ)または「パス_url」(httpなどから始まるフルパス)という形式でURL形式を指定できます。たとえばContactページが/contactというパスにある場合、
contact_path
またはcontact_url
という名前付きルートで指定できます。名前付きルートは、パスヘルパーやURLヘルパーとも呼ばれます。これにより、コード上でURL構造を意識せずにパスを指定できます。
なお似ているけど違うのは「名前付きスコープ」と「名前付きパラメータ」です。 - ネストしたリソース
- ネストしたルーティングを記述することで、あるリソースを他のリソースの子にすることができます。
ファイル分割を検討する
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"
アルファベット順にソートする
ネストしたリソースなどについては、後編に続きます。