はじめに
こんにちは。アメリカにて独学でエンジニアを目指している者です。
Railsでコントローラを実装していると、ビューを表示させたいときにはrender、別のアクションに転送したいときにはredirect_toを使う場面がよくあります。
この2つのメソッドは見た目こそ同じように「画面に何かを返す」ように見えますが役割や仕組みが大きく異なります。
本記事では、Railsにおけるrenderとredirect_toの違い、使い分けのポイント、そしてベストプラクティスについて解説します。
renderとredirect_toの基本的な違い
1. renderとは?
- その場でビューを表示する。
- 同一リクエスト内でテンプレートをレンダリング(描画)するので、リクエストは新規に発行されない。
-
URLは変わらない。例えば
/usersにPOSTリクエストを送信している最中にrender :newを行うと、ブラウザのアドレスバーは依然として/users(POST送信元)のままです。
典型的な使用例:バリデーションエラー時の再表示
def create
@user = User.new(user_params)
if @user.save
# 省略
else
# フォームの入力不備があればnewフォーム画面を再表示
render :new, status: :unprocessable_entity
end
end
上記のようにフォーム送信後にエラーがあった場合、すでに入力された値やエラーメッセージを表示するためにrender :newを使います。入力値を再利用できるように、同じリクエスト内でテンプレートを描画しているわけです。
2. redirect_toとは?
- ブラウザに対して別のURLを再度リクエストするよう命じる。
- HTTPステータスコードは通常「302 Found」や「303 See Other」(Railsによってリクエストの種類に応じて使い分け) が返され、ブラウザはその指示に従って別のアクションをGETリクエストとして再度呼び出します。
-
URLが変わる。たとえば
redirect_to @userと書くと、/users/:id(showアクション)へ転送されます。
典型的な使用例:リソースの作成や更新が成功した後
def create
@user = User.new(user_params)
if @user.save
flash[:success] = 'Welcome to the App!'
redirect_to @user # `/users/:id` へリダイレクト
else
render :new, status: :unprocessable_entity
end
end
新規作成が成功した場合などにredirect_toを使うのは、画面を再表示した際に再度POST(またはPATCH/PUT等)が送信される二重投稿を防ぐためです。これはPOST/REDIRECT/GETパターンと呼ばれ、実務でもよく使われます。
使い分けの理由
1. 二重投稿(POSTリクエストの再送信)防止
ユーザーがフォームを送信するときには、サーバーにPOSTリクエストが送られます。もしエラーではなく成功時にそのままrenderを使うと、ユーザーがページを更新(リロード)しただけで再度同じPOSTリクエストが送信されてしまいます。
これにより同じデータが重複して作成されるリスクがあるため、成功時はredirect_toで別のアクションへ飛ばし、ブラウザにGETリクエストを再送信させることがRailsの流儀になっています。
2. ユーザー体験(UX)の向上
redirect_toするとURLが正しくリソースを表すもの(例:/users/1)になるので、ユーザーがブックマークしたり、URLを共有したりするときに便利です。
renderの場合はURLが変わらず、フォーム送信時にエラーが出てもアドレスバーのURLが変わらないため、ユーザーにとってはどの画面を見ているかわかりにくいことがあります。しかし、入力エラーの際はその場でフォームとエラーメッセージを再表示したいので、render :newを用いるのは自然です(また別のURLにリダイレクトしてしまうと、エラー情報を渡す手間が増えてしまいます)。
3. RESTfulな設計
Railsの基本原則はRESTfulな設計です。
- 新規作成→POSTを受けて→
createアクション→成功時にredirect_to showへ - 更新→PATCH/PUTを受けて→
updateアクション→成功時にredirect_to showへ
こうした一連の操作はAPIとしても分かりやすく、コントローラ内のフローも整理しやすくなります。
サンプルコード:renderとredirect_toの使い所
ここでは簡単なUserモデルを例に示します。
class UsersController < ApplicationController
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
# 成功時:フラッシュメッセージをセットし、showアクションへリダイレクト
flash[:notice] = "User was successfully created."
redirect_to @user
else
# 失敗時:newアクションのフォーム画面を再表示
render :new, status: :unprocessable_entity
end
end
def show
@user = User.find(params[:id])
end
private
def user_params
params.require(:user).permit(:name, :email)
end
end
-
成功(バリデーション通過)
-
@user.saveがtrueを返す -
flash[:notice]にメッセージを設定 -
redirect_to @userが呼ばれ、ブラウザは/users/:idへGETリクエストを送る - コントローラは
showアクションが呼ばれ、詳細ページを表示
-
-
失敗(バリデーションNG)
-
@user.saveがfalseを返す -
render :newを呼び出し、同じリクエスト内でnewビューを描画 -
@userにはエラー情報が入っているため、ビューでエラーメッセージが表示される - URLは
/users(POST送信先)のまま変わらないが、この場合はユーザーの入力エラーを即座に表示できるため利便性が高い
-
よくある質問と注意点
Q1. 成功時にrender :showではダメなの?
- 成功後に
render :showを使うことは技術的には可能ですが、フォームの二重投稿を防げないなどの問題が起きます。また、ユーザーのブラウザのURLがPOSTのままになり、リロードするとまたPOSTが実行される可能性があります。したがって**redirect_toを使うのがベストプラクティス**です。
Q2. バリデーションエラーのときにredirect_toしたい
- エラー情報や入力途中のフォーム内容を引き継ぐのが難しくなります。通常はリダイレクト先でエラーメッセージを表示するための仕組みが必要になるでしょう。
Railsの一般的なパターンは、エラー時はrender :newやrender :editで同じリクエスト内でエラー表示をすることです。
Q3. renderとredirect_toどちらがパフォーマンスに優れているの?
- どちらを選ぶかはアプリのフローで決めるべきで、パフォーマンスが決定的な要因になることはほとんどありません。むしろ二重送信やユーザーの操作性を考慮した上で選択するのが重要です。
Q4. redirect_to先を動的に変更したい
- Railsでは
redirect_to user_path(@user)のようにヘルパーメソッドを使ってURLを動的に生成できます。redirect_to @userはこのヘルパーを裏で使っているので、オブジェクトを渡すだけで適切なパスを計算してくれます。
まとめ
-
render: 同じリクエスト内でテンプレートを描画。URLはそのまま。バリデーションエラー時のフォーム再表示などに使う。 -
redirect_to: ブラウザが改めて別のURLにアクセス。URLが変化し、二重投稿防止にもなる。成功時の処理や別ページへの誘導に使う。
Railsでは「失敗時はrender、成功時はredirect_to」が基本パターンと言えます。これはユーザー体験向上やデータの重複作成防止につながるためです。