【Rails入門説明書】redirect_toについて解説
はじめに
リダイレクトは、ブラウザからのリクエストに対して、別のURLを呼び出すように要求することです。
そもそもWebアプリケーションでは、自動的にページ遷移させる動作は、決して少なくありません。
例えば、以下のような場合が考えられます。
・処理後にトップページを表示する
・アクセス条件を満たせなかった場合に、別のサイトへ遷移させる
・ページの改修中に、一時的に別ページへ遷移させる
そんな、ユーザビリティを損なうことなく、自動的にページ遷移させる機能を実現するredirect_toメソッドについて、詳しく解説いたします。
redirect_toの挙動
リダイレクトの、「ブラウザからのリクエストに対して、別のURLを呼び出すように要求する」という動きを実感していただくため、実際に動かしながら確認していきましょう。
環境構築
コマンドプロンプトにて、以下のコマンドを実行してください。
[bash]rails new redirect_test
cd redirect_test
rails generate scaffold Item title:string price:integer
rake db:migrate
[/bash]
サーバを起動(rails sコマンド)して、テスト環境の動作を確認しておきます。
ブラウザで「localhost:3000/items」へアクセスしてください。
「Create User」をクリックして、登録画面へ遷移してください。
上記のようにデータを入力後、「Create Item」をクリックすると、登録したデータの詳細画面が表示されます。
その後、「Back」をクリックすることで、一覧画面へ戻ってくるようになっているのです。
リダイレクトさせる
では、テスト環境での画面遷移を、redirect_toを使って変えてみましょう。
例えば、データ登録(「Create Item」をクリック)した後に、詳細ではなく一覧画面へ遷移させてみます。
リクエストに対する動作を定義しているのは、routesですので、routesを確認してみましょう。
[code language=”bash”]”]>rails routes
Prefix Verb URI Pattern Controller#Action
items GET /items(.:format) items#index
POST /items(.:format) items#create
new_item GET /items/new(.:format) items#new
edit_item GET /items/:id/edit(.:format) items#edit
item GET /items/:id(.:format) items#show
PATCH /items/:id(.:format) items#update
PUT /items/:id(.:format) items#update
DELETE /items/:id(.:format) items#destroy
[/code]
データ登録はフォームの入力ですので、POSTリクエストです。
POSTリクエストに対する動作は、createアクションが定義されていますので、今回修正するのはコントローラのcreateメソッドになります。
(app/controllers/items_controller.rb)
:
def create
@item = Item.new(item_params)
respond_to do |format|
if @item.save
format.html { redirect_to @item, notice: ‘Item was successfully created.’ }
format.json { render :show, status: :created, location: @item }
else
format.html { render :new }
format.json { render json: @item.errors, status: :unprocessable_entity }
end
end
end
:
[/code]
登録時は「@item.save」が成功した場合の動作ですから、上の分岐に流れます。そして、format.xxxxは、データがxxxx形式の場合の動作を定義していますので、上記のハイライトされている部分が登録後の画面遷移を実現している部分になります。
ここでは、すでにredirect_toメソッドが使われ、引数として登録したばかりのモデルである@itemが渡されています。じつは@itemは、特定のレコードを表しており、この場合、「”/items/#{@item.id}”」の簡略記載と解釈してくれます。(極めて、Railsらしい動作です)
つまり、この部分で「localhost:3000/items/1」へリダイレクトしているということになります。
そのため、一覧画面へリダイレクトさせるため、この引数を一覧画面のURLである「/items」へ変更しましょう。
(app/controllers/items_controller.rb)
:
def create
@item = Item.new(item_params)
respond_to do |format|
if @item.save
format.html { redirect_to “/items”, notice: ‘Item was successfully created.’ }
format.json { render :show, status: :created, location: @item }
else
format.html { render :new }
format.json { render json: @item.errors, status: :unprocessable_entity }
end
end
end
:
[/code]
「localhost:3000/items/new」にアクセスして、データを登録してみましょう。
「Create Item」をクリックすると、一覧画面へ遷移します。
https://web-camp.io/magazine/archives/12481
redirect_toの構文といろいろなリダイレクト
前述のように、redirect_toメソッドはユーザーに意識させることなく、都合の良いページへ遷移させることができるメソッドです。
ページ遷移は、Railsアプリケーションの動きそのものですので、オリジナルのRailsアプリケーションを作る上で、redirect_toメソッドは比較的多く使うメソッドの1つと言えるでしょう。
構文
redirect_toメソッドの構文はとてもシンプルです。
redirect_to(リダイレクト先 [, :status => ステータスコード, 出力オプション])
リダイレクト先
リダイレクト先は、原則としてURLです。
しかし、URLを直接指定する方法では、もし遷移先に変更があった場合、変更するところがあちこちに存在してしまって、変更漏れやミスの原因になりかねません。
そのため、redirect_toメソッドの引数には、URLを直接指定するだけではなく、アクションを指定することもできるようになっています。
いくつかのパターンがありますので、紹介しておきましょう。
1.URLへリダイレクト
もっとも単純なリダイレクトです。外部サイトのURLを指定することもできます。
redirect_to URL
2.アクションを指定したリダイレクト
特定のアクションを指定することで、リダイレクト先を指定する方法です。
自コントローラ内の別アクションであれば、actionオプションにアクション名を指定するだけで、そのアクションへリダイレクトさせることができます。
redirect_to action: アクション名
controllerオプションでコントローラ名を指定することで、別のモデルのアクションへリダイレクトさせることもできます。
redirect_to controller: コントローラ名, action: アクション名
また、idオプションを指定すれば、リダイレクト先のアクションへidを渡すことも可能です
redirect_to controller: ‘コントローラ名, action: アクション名, id: id
3.前ページへリダイレクト
1つ前のページへ戻るというのは、使用頻度が高いこともあって、特別に用意されています。
redirect_to :back
ただし、この方法はRails5.1以降では、以下のredirect_backへ置き換わりました。気を付けましょう。
redirect_back
“未経験”でもたった1ヶ月で営業からエンジニアとして転職!『WebCamp』受講者インタビュー
ステータスコード
ステータスコードというのは、ブラウザからのリクエストに対して、サーバが返す処理結果を表す値です。(正確には、HTTPステータスコードと呼びます)
ブラウザは、受け取ったステータスコードを見て、様々な動作を行う仕様になっています。
そのため、redirect_toメソッドでも、ステータスコードを返す必要があります。そのためのオプションが「:status => ステータスコード」なわけです。
ただし、redirect_toメソッドでリダイレクトをした場合、302(リクエストしたリソースを別の場所で発見した)が返されます。そのため、画面遷移を目的としたリダイレクトの場合は、statusオプションを使用する必要はないでしょう。
念のため、302が返されていることを確認しておきましょう。
前項で確認した「Create Item」をクリックした後、コマンドプロンプトを確認すれば、以下のようなログが出力されています。
[bash]:
Redirected to http://localhost:3000/items
Completed 302 Found in 870ms (ActiveRecord: 52.9ms)
:
[/bash]
多くの書籍や解説サイトで302は「リクエストしたリソースは一時的に移動した」といった説明がされてますが、現在は変更されています。現在は、意図的なページの変更に302が使われており、「一時的な移動」という解釈のステータスコードとしては、307が追加されています。
そのため、Railsのデフォルトの動きがずれているわけではありませんので、ご安心ください。
他にも、HTTPステータスコードは多数ありますが、使うことの多いステータスコードと、シンボルを紹介しておきましょう。
シンボル | ステータスコード | 概要 |
---|---|---|
:ok | 200 | リクエストは成功、要求に応じたレスポンスを返却 |
:created | 201 | リクエストは成功、新規作成されたリソースのURIを返却 |
:moved_permanently | 301 | 恒久的なリソースの移動 |
:found | 302 | リクエストしたリソースを別の場所で発見した |
:not_modified | 304 | リクエストしたリソースは更新されていない |
:temporary_redirect | 307 | 一時的なリソースの移動 |
:bad_request | 400 | リクエストが不正 |
:unauthorized | 401 | 認証が必要 |
:forbidden | 403 | リソースへのアクセスは禁止 |
:not_found | 404 | リソースが見つからない、もしくはアクセス権がない |
:not_acceptable | 406 | 指定されたフォーマットでレスポンスを返せない |
:unprocessable_entity | 422 | バリデーションエラー |
:internal_server_error | 500 | サーバの内部エラー |
:service_unavailable | 503 | メンテナンスや高負荷などでレスポンスを返せない |
意図的なページ遷移以外のリダイレクトの場合に、これらの中から適切なステータスコードを設定することで、ブラウザが想定外の動きをすることを防ぐことができます。
なお、statusオプションには、シンボルとステータスコードのどちらを設定してもかまいません。
例えば、以下のように変更すれば、内部エラー500を返すことができます。
(app/controllers/items_controller.rb)
:
def create
@item = Item.new(item_params)
respond_to do |format|
if @item.save
format.html { redirect_to “/items”, :status => 500 }
format.json { render :show, status: :created, location: @item }
else
format.html { render :new }
format.json { render json: @item.errors, status: :unprocessable_entity }
end
end
end
:
[/code]
(ログ)
[bash]:
Redirected to http://localhost:3000/items
Completed 500 Internal Server Error in 50ms (ActiveRecord: 37.9ms)
:
[/bash]
メッセージ表示
メッセージは、すでにテスト環境で以下のように使用されています。
.. notice: ‘Item was successfully created.’
実行したときに表示されていますので、改めて確認してみましょう。
「localhost:3000/items/new」にアクセスして、「Create Item」をクリックすると、一覧画面へ遷移して、「noticeオプション」で設定した文字列が表示されているのが確認できるでしょう。
テスト環境では、処理結果を表示していますので、noticeオプションを使用していますが、他にもエラーメッセージを表示するalertオプションや任意のパラメータを渡してViewファイルで表示できるflashオプションがありますので、まとめておきます。
メッセージオプション | 説明 |
---|---|
:alert => メッセージ | エラーメッセージを表示 |
:notice => メッセージ | 通知用のメッセージを表示 |
:flash => {パラメータ => 値} | パラメータを使って、一時的に値を保存 値を表示したければ、Viewファイルでflash[パラメータ]を呼び出すことで表示できる |
flashオプションで表示する場合を、試してみましょう。
(app/controllers/items_controller.rb)
[code language=”ruby” highlight=”7″]:
def create
@item = Item.new(item_params)
respond_to do |format|
if @item.save
format.html { redirect_to “/items”, :flash => {:msg => “Created!”} }
format.json { render :show, status: :created, location: @item }
else
format.html { render :new }
format.json { render json: @item.errors, status: :unprocessable_entity }
end
end
end
:
[/code]
(app/views/items/index.html.erb)
[code language=”html” highlight=”4″]<p id=”notice”><%= notice %></p>
<h1>Items</h1>
<%= flash[:msg] %>
:
[/code]
新しいitemを追加(「Create Item」クリック)すると、flashオプションで指定した「Created!」がタイトルの下に表示されています。
https://web-camp.io/magazine/archives/12654
renderとの違いとredirect_toの使いどころ
redirect_toメソッドと同じように、ブラウザがリクエストしたページのリソースではないリソースを表示するメソッドに、renderメソッドがあります。
両方とも、別のページを表示するという意味では同じですので、混乱している人も多いかもしれません。
そこで、最後にこれらのメソッドの違いと、使いどころを説明しましょう。
redirect_toメソッドの動き
ここまで説明してきたように、redirect_toメソッドは、ブラウザに対して指定した遷移先へのリクエストの再要求を促すもので、改めて別ページへ遷移しています。
つまり、リダイレクト前に、コントローラで定義した変数やフォームで入力したデータなどを使用することはできませんので、注意が必要です。
renderメソッドの動き
renderメソッドは、見た目はredirect_toメソッドと同じように見えますが、じつは表示するテンプレートだけ指定されたページのものを使っているだけです。
つまり、実際は登録画面だが、表示は一覧を表示しているということも実現可能です。しかし、変数などは登録画面用のコントローラで定義したものしか使えません。(一般的に登録画面では一覧画面に表示するような複数レコードのデータを保持していません)
それぞれの使いどころ
もっとも大きな違いは、実態として遷移しているかどうかです。
実態として遷移しているということは、その先の遷移も正常に進められます。しかし、実態は遷移しておらず、表示上だけ遷移しているように見える場合は、その先の遷移が正常に行える保証がありません。
例えば、登録画面で入力漏れなどがあってやり直す場合、redirect_toメソッドで登録画面へリダイレクトしてしまうと、すべての入力データがクリアされてしまいます。そのため、renderメソッドを使って表示だけ戻し、保持していたデータを戻した方が、ユーザビリティは高くなるでしょう。
逆に、登録後の画面(詳細画面や一覧画面)をrenderメソッドで表示してしまうと、その後のページ遷移に不整合が出る可能性が高いと言えます。
つまり、redirect_toメソッドとrenderメソッドの使い分けは以下のようになるでしょう。
redirect_toメソッド | 遷移後に登録や修正など別のページ遷移が続くシーン |
---|---|
renderメソッド | 一時的に情報を確認するだけのようなシーン |
まとめ
redirect_toメソッドについて、説明しました。
redirect_toメソッドは、Railsアプリケーションの画面遷移を自動的に行う場合に活躍するため、使用頻度が高いメソッドの1つでしょう。
使い方も非常にシンプルで、使いやすいメソッドの1つと言えるでしょう。
ただし、実際に使いこなすには、自分で画面遷移を設計し、それに合わせて諸々のファイルを揃える必要があります。そのため、面倒に感じるかもしれませんが、そういった作業を行うことで、Railsアプリケーションの処理の流れを把握することができます。
処理の流れの把握は、すぐに役に立つわけではありませんが、いざというときには非常に強力な武器になります。
ぜひ、チャレンジして中級プログラマを目指しましょう。
・リダイレクトは、ブラウザからのリクエストに対して、別のURLを呼び出すように要求すること
・redirect_toメソッドは、リダイレクトを実現する
・redirect_toメソッドでは、URL、アクションを使ってリダイレクトする。他のモデルのアクションへもリダイレクトできる
・Rails5.1以降は1つ前へ戻るのに、redirect_backメソッドを利用する
・redirect_toメソッドは、デフォルトでステータスコード302を返す
・redirect_toメソッドは、ブラウザからのリクエストを再送させ、完全にページ遷移する
・renderメソッドは、ページ遷移せず、他のページのViewファイルを使って表示する
【インタビュー】1ヶ月でRubyをゼロから学び、Webエンジニアとして転職!
ブラジルから帰国し技術をつけようとRubyエンジニアを目指してWebCampでRubyを学び、見事Webエンジニアとして転職を果たした田中さんにお話を伺いました。
「Rubyの学習がしたい。基礎をしっかりと理解したい」
「転職のサポートがほしい」
と考えている方はぜひお読み下さい。
https://web-camp.io/magazine/archives/8535