こんにちは、かつコーチです。
routes.rb に resources :posts と1行書くだけで、たくさんのルートが自動生成される。
初めて見たとき「便利だけど、結局何が作られているのかわからない」と感じませんでしたか。
私も最初は rails routes の出力を見ても、どのアクションがどのURLに対応するのか整理できませんでした。
この記事では、RESTful(リソースをURLとHTTPメソッドの組み合わせで統一的に表現する設計思想です)という考え方と、resources が自動生成する7つのルートを、実際のコードとセットで解説します。
読み終えるころには、なぜRailsが resources を標準にしているのか腹落ちしているはずです。
RESTfulとは?
リソース指向の考え方
REST(Representational State Transfer)とは、Webサービスを「リソース」(データのまとまり、例えば「投稿」や「ユーザー」)の集合として捉え、それに対する操作をHTTPメソッドで表現する設計思想です。
例えば「投稿」というリソースに対する操作は、次のように整理できます。
| 操作 | HTTPメソッド | 意味 |
|---|---|---|
| 一覧を見る | GET | 投稿一覧を取得する |
| 詳細を見る | GET | 特定の投稿を取得する |
| 新規作成する | POST | 投稿を新しく作る |
| 更新する | PATCH/PUT | 投稿を書き換える |
| 削除する | DELETE | 投稿を消す |
URLは「何のリソースか」だけを表し、「何をするか」はHTTPメソッドが表す。
これがRESTfulな設計の基本です。
なぜRailsはresourcesを推奨するのか
RESTfulな設計にすると、URLの命名に迷わなくなります。
「投稿を編集する画面のURLは /posts/edit_form かな、それとも /posts/1/edit かな」と毎回考える必要がなくなるからです。
Railsは「設定より規約」という思想のフレームワークなので、この規約に沿ったURL設計を resources 1行で実現できるようにしています。
resources :xxxで自動生成される7つのルート
実際に書いてみる
まずは config/routes.rb に以下を追記します。
# config/routes.rb
Rails.application.routes.draw do
resources :posts
end
この1行だけで、以下の7つのルートが自動生成されます。
$ bin/rails routes -g posts
Prefix Verb URI Pattern Controller#Action
posts GET /posts posts#index
POST /posts posts#create
new_post GET /posts/new posts#new
edit_post GET /posts/:id/edit posts#edit
post GET /posts/:id posts#show
PATCH /posts/:id posts#update
PUT /posts/:id posts#update
DELETE /posts/:id posts#destroy
7つのアクションと役割
| アクション | 役割 | 対応するURL例 |
|---|---|---|
| index | 一覧表示 | GET /posts |
| show | 詳細表示 | GET /posts/1 |
| new | 新規作成フォーム表示 | GET /posts/new |
| create | 新規作成の実行 | POST /posts |
| edit | 編集フォーム表示 | GET /posts/1/edit |
| update | 更新の実行 | PATCH /posts/1 |
| destroy | 削除の実行 | DELETE /posts/1 |
コントローラ側は、この規約に沿ってアクションを定義するだけです。
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
def index
@posts = Post.all
end
def show
@post = Post.find(params[:id])
end
def new
@post = Post.new
end
def create
@post = Post.new(post_params)
if @post.save
redirect_to @post, notice: "投稿を作成しました。"
else
render :new, status: :unprocessable_entity
end
end
def edit
@post = Post.find(params[:id])
end
def update
@post = Post.find(params[:id])
if @post.update(post_params)
redirect_to @post, notice: "投稿を更新しました。"
else
render :edit, status: :unprocessable_entity
end
end
def destroy
@post = Post.find(params[:id])
@post.destroy
redirect_to posts_path, notice: "投稿を削除しました。", status: :see_other
end
private
def post_params
params.require(:post).permit(:title, :body)
end
end
パスヘルパーを使う
rails routes の出力にある Prefix 列(posts、new_post など)は、パスヘルパー(URLを直接書かずに済むメソッドです)の元になります。
<%# app/views/posts/index.html.erb %>
<%= link_to "新規投稿", new_post_path %>
<% @posts.each do |post| %>
<%= link_to post.title, post_path(post) %>
<% end %>
URLを文字列で直接書いてしまうと、後でルーティングを変更したときに全ファイルを修正する必要が出てきます。
パスヘルパーを使えば、その心配がありません。
よくあるつまずきポイント・エラー対処
全アクションを自動生成してしまい、使わないルートが残る
❌ Before:使わないアクションまで含めて全公開してしまう
# config/routes.rb
Rails.application.routes.draw do
resources :posts
end
管理者しか使わない destroy まで誰でも呼び出せる状態になっていないか、必ず確認しましょう。
実際に私は、削除機能をまだ実装していない段階で resources :posts とだけ書いてしまい、フォームもコントローラもない destroy のルートだけが存在するという中途半端な状態にしてしまったことがあります。
エラーにはなりませんが、rails routes で見たときに「これは本当に必要なアクションか」を毎回意識するようにしています。
✅ After:必要なアクションだけをonly/exceptで絞り込む
# config/routes.rb
Rails.application.routes.draw do
resources :posts, only: [:index, :show, :new, :create]
end
管理画面など、更新・削除も必要な場合は逆に except で絞り込むと読みやすくなります。
# config/routes.rb
Rails.application.routes.draw do
namespace :admin do
resources :posts, except: [:new, :create]
end
end
必要なアクションだけを明示することで、意図しないルートの公開を防げますし、rails routes の出力も見やすくなります。
まとめ
この記事のポイント
- RESTfulとは、URLとHTTPメソッドでリソースへの操作を統一的に表現する設計思想
resources :postsで index/show/new/create/edit/update/destroyの7ルートが自動生成される- パスヘルパー(
posts_pathなど)を使うとURLの変更に強いコードになる only/exceptで不要なルートを絞り込み、意図しない公開を防ぐ
次に読むべき記事
- ルーティングの基本:config/routes.rbの書き方
- コントローラの基本:アクションとストロングパラメータ
タグ: Ruby on Rails, 中級者向け, フレームワーク基礎