認可機能によって、ログインしていないユーザーが編集ページにアクセスしようとすると、ログインページにリダイレクトされる。
その後ログインするとプロフィールページに移動するが、ここでもともとアクセスしようとしていた編集ページに移動してくれると親切である。
これをフレンドリーフォワーディングと呼ぶ。
フレンドリーフォワーディングのテスト
フレンドリーフォワーディングは少し複雑なので、テスト駆動開発で進める。
編集成功時のテストを修正する。
test "successful edit with friendly forwarding" do
get edit_user_path(@user)
log_in_as(@user)
assert_redirected_to edit_user_url(@user)
name = "Foo Bar"
email = "foo@bar.com"
patch user_path(@user), params: { user: { name: name,
email: email,
password: "",
password_confirmation: "" } }
assert_not flash.empty?
assert_redirected_to @user
@user.reload
assert_equal name, @user.name
assert_equal email, @user.email
end
編集ページにアクセス→ログインページにリダイレクトしてログイン→編集ページにリダイレクト、という流れになる。
フレンドリーフォワーディングの実装
store_locationとredirec_back_orメソッド
ユーザーを希望のページに転送するには、リクエスト時点のページを保存しておく必要がある。
# 記憶したURL (もしくはデフォルト値) にリダイレクト
def redirect_back_or(default)
redirect_to(session[:forwarding_url] || default)
session.delete(:forwarding_url)
end
# アクセスしようとしたURLを覚えておく
def store_location
session[:forwarding_url] = request.original_url if request.get?
end
store_locationメソッドでは、session[:forwarding_url]に、リクエスト先を取得するrequest.original_urlを入れる。
この時、セキュリティ上の問題を解決するために、request.getを使ってGETリクエストの場合のみとする。
redirect_back_orメソッドでは、or演算子||を使って、session[:forwarding_url]がある場合はそちらにリダイレクトし、無い場合は引数のURLにリダイレクトする。
リダイレクト後はsession[:forwarding_url]を削除しておく。
store_locationメソッドを使って、非ログイン時に編集ページにアクセスしたらURLを保存する。
# beforeアクション
# ログイン済みユーザーかどうか確認
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
redirect_back_orメソッドを使って、ログイン後に保存したURLにリダイレクトする。
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
log_in user
params[:session][:remember_me] == '1' ? remember(user) : forget(user)
redirect_back_or user
else
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
end