2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Railsチュートリアル7章:user作成後にredirectする理由

Posted at

railsチュートリアルの7章では、実際にブラウザからリクエストを送信し、ユーザー登録ができるようにします。
その際、UsersControllerのcreateメソッドは以下のようにしました。

users_controller.rb
def create
    @user = User.new(user_params)
    if @user.save
        flash[:success] = '<メッセージ>'
        redirect_to @user # user詳細にredirectする
    else
        render 'new', status: :unprocessable_entity
    end
end

チュートリアル内ではざっと以下のように説明されています。

  1. redirectなどの処理がない状態でブラウザからリクエスト
  2. → エラーとなり、原因はcreateに対応するviewファイルがないこと
  3. ただ、webアプリではcreateなどの操作後は詳細ページなどにリダイレクトするのが一般的で、そちらを採用する

という感じです。
画面の動き的にもしっくりくるのであまり気にしていませんでしたが、ふとどうしてリダイレクトが一般的なのだろうと思い調べたので、記憶定着 & 備忘録としての記事になります。

なぜ、user作成などの後はredirectするのか?

結論、リロード(など)をした場合に再度postメソッドを送信してしまう心配がない ため、安全であるということかなと思います。

ここで、redirectをした場合としなかった場合のリクエストの流れが重要になります。

redirectをしない場合

例えば、createに対応するviewファイルがあったとします。その場合、以下のような順序でcreate viewが表示されます。

  1. クライアント(ブラウザ)から、user作成リクエスト(POST)が送信される
  2. UsersController#createで、user作成が成功し、create viewが返される
  3. クライアント側でcreateページが表示され、終了

という形です。この場合、1度のリクエストで全てが完結します

redirectの場合

では、次にredirectをした場合をみます。

  1. クライアント(ブラウザ)から、user作成リクエスト(POST)が送信される
  2. UsersController#createで、user作成が成功しUsers#showにもう一度リクエストしてね!(リダイレクトしてね!)というレスポンスが返される
  3. クライアントは、それに従いユーザー詳細ページをリクエスト(GET)する
  4. Users#showでshow viewが返される
  5. クライアント側でshowページが表示される

このように、ブラウザの操作では一度のみリクエストしているように見えるものの、動作的には2度のリクエストがなされ、終了します。

じゃあ、どうして安全なの?

というところですが、ブラウザでのリロードは「前回のリクエストを再送信する」という動作をします。よってredirectをしない場合、画面をリロードすると前回のリクエストである「User作成リクエスト(Post)」をもう一度実行することになります。
すると、意図せず再度リクエストをするといったことが発生しやすくなり、安全ではありません。
ブラウザで「再度送信しますか?」などのアラートがと出るのは、こういった動作で再リクエストしようとしている時、危ないから確認してね、という注意喚起ですね。
※上記の通り、表示されているurlにgetを送るといった動作でないことに注意でしょうか。

ところがredirectを利用すると、最後のリクエストがgetメソッドとなり、リロードした際意図せずデータを作成してしまう、などのいわば事故が発生しなくなります。
ですのでベーシックなwebアプリでは、基本的にDBへ変更のあるリクエストが完了した際はリダイレクトをするのが一般的、ということだと思います。

また、そのことをPRG(Post - Redirect - Get)パターンと言ったりもするそうです。

余談

ではもし、create後に「完了ページ」のようなものを特別用意したいといった場合はどうするのだろう?と思いましたが、単純にUsersController#completeメソッド + complete テンプレートを作成し、そこにredirectすれば良い、ということでした。
確かに。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?