Edited at

ログインしてないときにアクセスした画面に戻りたい、GET以外でも。

More than 5 years have passed since last update.

deviseの話です。

routes.rbにはこんなかんじの定義があるとします。


confg/routes.rb

devise :users

resources :events do
resource :attendances, only: [:create, :destroy] # 参加処理
end

例えば、/events/new にアクセスするにはuserの認証が必要。そんな時はコントローラーに以下のように書きますよね。


app/controllers/events_controller.rb

class EventsController < ApplicationController

before_action :authenticate_user!, only: [:new] # rails3 以下なら before_filter
def show
# イベント表示処理
end

def new
# イベント作成準備処理
end
end


この時、ログインしてない状態で、/events/new に アクセスすると、ログインしていないのでnew_user_session_path にリダイレクトされますね。

んで、ログインした跡は、/events/new に戻ってこれる。よい。deviseよい。

今度は、イベント参加時にuserの認証が必要。そんな時は以下。


app/controllers/attendances_controller.rb

class AttendancesController < ApplicationController

before_action :set_event
before_action :authenticate_user! # rails3 以下なら before_filter

def create
# イベント参加処理
end

def destroy
# イベント参加キャンセル処理
end

private
def set_event
@event = Event.find(params[:event_id])
end
end


/events/:idviewに、こんなボタンが置いてあるイメージです。


app/views/show.html.haml

= link_to(event_attendances_path(@event), method: :post, class: 'btn') do

= t('nav.attendaces.create')

この時、ログインしてない状態でこの参加ボタンをクリックすると、/events/:id/attendancesPOST するわけですが、ログインしていないのでnew_user_session_path にリダイレクトされますね。

んで、ログインすると、root_path に戻ってしまうのがだるい。おれの参加したかったイベントよ、、、どこへ。本当なら、/events/:id に戻りたいですよねーということで、そんな時どうするか。(前置きの長さよ)


磯野〜ソース読もうぜ〜

deviseのソースを読みましょう。

https://github.com/plataformatec/devise/blob/10c9a492ab27f48d66f50df7f1e7f5e8c68f2b0f/lib/devise/failure_app.rb#L183

session["#{scope}_return_to"] = attempted_path if request.get? && !http_auth?

なるほどね、っと。session[:user_return_to] に、/events/:id を入れておけばうまくいきそうです。


イベント参加ボタンクリック後に、イベントページに戻る

参加処理のbefore_actionsession[:user_return_to] に、/events/:id を入れる処理をかきます。


app/controllers/attendances_controller.rb

class AttendancesController < ApplicationController

before_action :set_event
before_action :store_event_url # 追加!
before_action :authenticate_user! # rails3 以下なら before_filter

def create
# イベント参加処理
end

def destroy
# イベント参加キャンセル処理
end

private
def set_event
@event = Event.find(params[:event_id])
end

# 追加!
def store_event_url
session[:user_return_to] = event_path(@event) unless user_signed_in?
end
end


はい。こんな感じです。deviseの使っているsessionの中身を書き換えるのは怖いよ〜という方は好きにして下さい。