目次
この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
Rails の Devise でログイン後にログインする直前のPOSTリクエストにリダイレクトさせます。
■ 目標
RailsでPOSTリクエストではリダイレクトできないため、deviserログイン後はGETリクエストのみリダイレクトできます。
下記の場合、お気に入り登録が出来ないし、お気に入り一覧にリダイレクトできないです。
未ログイン⇒商品詳細⇒お気に入り登録(POST)⇒ログイン画面⇒ログインする⇒お気に入り一覧
■ 対策
POSTなので、直接遷移が出来なくて、after_login_to_postを作成して、その後自動サブミットすれば、POSTリクエストにリダイレクトを実現します。
動き:
未ログイン⇒商品詳細⇒お気に入り登録(POST)⇒ログイン画面⇒ログインする⇒after_login_to_post⇒真っ白ページ(自動サブミット)⇒お気に入り一覧
■ セッションに POST リクエストのパラメータを保存
POSTリクエスト中で、POSTリクエストのパラメータ、コントローラ、アクションをセッションに保存します。
class CustomersFavoritesController < ApplicationController
before_action :authenticate_customer!, except: :create
def create
if current_customer.signed_in?
current_customer.favorites.create(product_id: params[:id]) unless current_customer.favorites.find_by(product_id: params[:id])
redirect_to action: :index
else
#セッションに POST リクエストのパラメータを保存
session[:after_login_to_post] = {
controller_name: controller_name,
action_name: action_name,
params: { id: params[:id] }
}
redirect_to new_customer_session_path
end
end
end
■ ログイン後のリダイレクトをカスタマイズ
ログイン後、セッションにPOST情報があれば、after_login_to_post_pathにリダイレクトさせます。
class CustomersSessionsController < Devise::SessionsController
# ログイン後、リダイレクト先メッソドafter_sign_in_path_forをオーバーライドする。
def after_sign_in_path_for(resource)
#お気に入り登録(POST)の場合、after_login_to_post_pathに遷移します。
if session[:after_login_to_post]
after_login_to_post_path
else
super
end
end
end
■ ログイン後にセッション情報からログイン直前のページ情報を復元
セッション情報から、POSTリクエストの情報を取得し、設定します。
class TopController < ApplicationController
def after_login_to_post
#セッションにafter_login_to_postがあれば、
if session[:after_login_to_post]
@back_controller = session[:after_login_to_post]['controller_name']
@back_action = session[:after_login_to_post]['action_name']
@params = session[:after_login_to_post]['params']
#セッションをクリア
session[:after_login_to_post] = nil
render :after_login_to_post, layout: false
else
#直接アクセスが来たら、TOPに遷移する。
redirect_to top_path
end
end
end
■ 真っ白VIEW
after_login_to_postのVIEWは自動サブミットします。
一瞬だけ真っ白なページが表示されますが、
自動サブミットによって、POST送信が出来ます。
after_login_to_post.slim
doctype transitional
html[xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja" dir="ltr"]
head
meta[http-equiv="Content-Type" content="text/html; charset=UTF-8"]
title = '戻る'
body onLoad="document.forms[0].submit()"
- if @back_controller && @back_action && @params
= form_tag( { controller: @back_controller, action: @back_action }, { method: 'post' } ) do
= hidden_field_tag 'id', @params['id']
<noscript>
= button_tag '戻る', class: 'btn_sub'
</noscript>
■ routes
### ログイン後、POSTアクションに戻る ###
get 'after_login_to_post', to: 'top#after_login_to_post'