はじめに
こんにちは。アメリカにて独学でエンジニアを目指している者です。
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
」が基本パターンと言えます。これはユーザー体験向上やデータの重複作成防止につながるためです。