Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Railsのルーティングを極める(前編)

更新情報

  • 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をインストールする必要があります)。

Rails: ルーティングを動的にビジュアル表示する方法

改めて、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" 

関連記事

Railsのルーティングを極める (後編)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。