目的
Railsチュートリアル10.2.3章では「フレンドリーフォワーディング」について学んでいきます。
https://railstutorial.jp/chapters/updating_and_deleting_users?version=6.0#sec-friendly_forwarding
ただこの章、初学者にとって理解しにくい箇所だと思ったので自分のためにもまとめておきます。
最終的にはリスト10.29のテストをより詳細にし、ふりがなを振っていきます。
前提
リスト10.33まで進め、リスト10.29のテストコードがGREENになる状態にしておいてください。
解説
そもそもこのテストで何をしようとしているのか?
リスト10.29にふりがなを振っていきます。
require 'test_helper'
class UsersEditTest < ActionDispatch::IntegrationTest
# @userにfixturesで定義したmichaelを代入
def setup
@user = users(:michael)
end
.
.
.
test "successful edit with friendly forwarding" do
# ログイン前にmichaelのユーザー編集ページにアクセス
get edit_user_path(@user)
# users_cotrollerのbeforeactionで設定されたlogged_in_userによりログイン画面に飛ばされる
# このとき、アクセスしようとしていた/users/:id/editのurlがstore_locationメソッドによりsession[:forwarding_url]に保存される
# flashが表示される
# @userとしてログインする
log_in_as(@user)
# redirect_back_or(default)メソッドにより@userのユーザー編集画面にリダイレクトする
assert_redirected_to edit_user_url(@user)
# redirect_back_orメソッドによりforwarding_urlは破棄される
# nameとemailを定義
name = "Foo Bar"
email = "foo@bar.com"
# paramsに下記情報を入れ、ユーザー情報を編集
patch user_path(@user), params: { user: { name: name,
email: email,
password: "",
password_confirmation: "" } }
# ユーザー情報が編集されたことを表すflashが表示される
assert_not flash.empty?
# @userのページにリダイレクトされる
assert_redirected_to @user
# @userの中身を確認
@user.reload
# @user.nameが上で定義したnameに更新されている
assert_equal name, @user.name
# @user.emailが上で定義したemailに更新されている
assert_equal email, @user.email
end
end
ということになります。
get edit_user_path(@user)
とlog_in_as(@user)
の間、結構省略されてると思いませんか?
ここを詳細に見ていきます。
logged_in_userでは何が行われているのか?
get edit_user_path(@user)
のあと、logged_in_userがおこなわれます。
users_controllerで設定されたlogged_in_userの中身を見ていきましょう。
# ログイン済みユーザーかどうか確認
def logged_in_user
# sessions_helperで定義したlogged_in?メソッドがfalse(ログインしていない)とき
unless logged_in?
# sessions_helperで定義したstore_locationをおこなう
store_location
# flashを表示させる
flash[:danger] = "Please log in."
# ログイン画面にリダイレクトする
redirect_to login_url
end
end
ここで、store_locationというメソッドがでてきました。
この中身も確認しましょう。
# アクセスしようとしたURLを覚えておく
def store_location
# getリクエストが送られたとき、そのときのurlをsession[:forwarding_url]に保存する
session[:forwarding_url] = request.original_url if request.get?
end
以上を踏まえると、
ログインしていない状態でusers_controllerのlogged_in_userが設定されたurlにアクセスすると
そのurlを保存し、ログイン画面に移る。
ログイン後は保存したurlに飛ぶ。
ということになります。
redirect_back_or(default)では何がおこなわれているのか?
log_in_as(@user)
のあと、sessions_controllerのcreateアクション内のredirect_back_or(default)メソッドが実行されます。
redirect_back_or(default)メソッドの中身を見ていきましょう。
このメソッドはsessions_helperにて定義されています。
# 記憶したURL(もしくはデフォルト値)にリダイレクト
def redirect_back_or(default)
# 保存したurlもしくはdefaultのurlにリダイレクトする
redirect_to(session[:forwarding_url] || default)
# 保存したurlを削除する
session.delete(:forwarding_url)
end
まとめると、
ユーザー編集ページにて情報を送信したあとのリダイレクト先は、
session[:forwarding_url]があるなら保存されたurl、なければデフォルトのurlである。
このとき、session[:forwarding_url]は削除される。
ということになります。
リスト10.29をより詳細に書いてみよう
さて、ログイン前にユーザー編集画面にアクセスしたときの挙動が分かったところで、リスト10.29をより詳細に書いてみましょう。
詳細に書くことで挙動の理解を深め、定義したメソッドが正しく動いているかも同時にテストすることができます。
require 'test_helper'
class UsersEditTest < ActionDispatch::IntegrationTest
# @userにfixturesで定義したmichaelを代入
def setup
@user = users(:michael)
end
.
.
.
test "successful edit with friendly forwarding" do
# ログイン前にmichaelのユーザー編集ページにアクセス
get edit_user_path(@user)
# users_cotrollerのbeforeactionで設定されたlogged_in_userによりログイン画面に飛ばされる
assert_redirected_to login_url
# このとき、アクセスしようとしていた/users/:id/editのurlがstore_locationメソッドによりsession[:forwarding_url]に保存される
assert_not session[:forwarding_url].nil?
# flashが表示される
assert_not flash.empty?
# @userとしてログインする
log_in_as(@user)
# redirect_back_or(default)メソッドにより@userのユーザー編集画面にリダイレクトする
assert_redirected_to edit_user_url(@user)
# redirect_back_orメソッドによりforwarding_urlは破棄される
assert session[:forwarding_url].nil?
# nameとemailを定義
name = "Foo Bar"
email = "foo@bar.com"
# paramsに下記情報を入れ、ユーザー情報を編集
patch user_path(@user), params: { user: { name: name,
email: email,
password: "",
password_confirmation: "" } }
# ユーザー情報が編集されたことを表すflashが表示される
assert_not flash.empty?
# @userのページにリダイレクトされる
assert_redirected_to @user
# @userの中身を確認
@user.reload
# @user.nameが上で定義したnameに更新されている
assert_equal name, @user.name
# @user.emailが上で定義したemailに更新されている
assert_equal email, @user.email
end
end
このテストはGREENになります。
まとめ
テストの中身をより詳細に記載しました。
あるアクションを実行したときの挙動を自分の言葉で言語化できるようになるとより理解が深まりますね。