Deviseを使ってユーザー認証機能を作ったときに、もうちょっとよくするための方法メモ。Deviseは普通の実装するとログイン後は/にリダイレクトされる。それを別のURLにする方法はここに書いた。

Deviseでログイン後のURLを変える方法 - ぴよログ

では、ログインに必要なページのURLに直接アクセスがあったときはどうするか。流れとしてはこうなるのが望ましい。

  1. ログインが必要なページにアクセスがある
  • ユーザーにログインフォームを見せる
  • ログインが完了したら最初にアクセスしたURLへリダイレクト

ログインが必要かどうかはコントローラレベルで制御する。これはまあよくやるやつ。

 1# application_controller.rb
 2class ApplicationController < ActionController::Base
 3private
 4  def sign_in_required
 5    redirect_to new_user_session_url unless user_signed_in?
 6  end
 7end
 8
 9# hoge_controller.rb
10class HogeController < ApplicationController
11  before_action :sign_in_required
12  def index
13    # ...
14  end
15
16  def ...
17end	

全てのコントローラで共有するために、ApplicationControllerにsign_in_requiredというメソッドを定義する。これにはログインしていなければログインページヘリダイレクトする、と書かれている。このsign_in_requiredは各コントローラのbefore_actionで使い、指定したアクションを要ログインにできる。

ここまでの実装だと1と2までは実現できているが、最初に開こうとしたURLへのリダイレクトは実現されておらず、ユーザーとしては非常に面倒くさい。リダイレクト部分を実現するためには最初のURLを覚えておいて、ログイン後のURLを/ではなく別のURLに差し替えてあげる必要がある。

そこでApplicationControllerをさらに拡張する。

 1class ApplicationController < ActionController::Base
 2  before_action :store_location
 3
 4  private
 5
 6  def sign_in_required
 7    redirect_to new_user_session_url unless user_signed_in?
 8  end
 9
10  def store_location
11    return unless request.get? 
12    if (request.path != "/users/sign_in" &&
13        request.path != "/users/sign_up" &&
14        request.path != "/users/password/new" &&
15        request.path != "/users/sign_out" &&
16        !request.xhr?)
17      session[:previous_url] = request.fullpath 
18    end
19  end
20
21  def after_sign_in_path_for(resource)
22    session[:previous_url] || root_path
23  end  
24
25end

store_locationでURLを覚えておき、after_sign_in_path_forで覚えておいたURLを返すということをしている。そしてstore_locationを全てのアクションの【前】に呼び出している。

詳しいことは↓に書かれているが、ここの例ではstore_locationafter_filterに指定、つまり各アクションの後に呼んでいる。今回の例ではアクション中にログインページにリダイレクトされてしまうため、覚えておくURLが適切なものではなくなってしまう。そこでbefore_actionを指定することでなんとか実現している。

How To: Redirect back to current page after sign in, sign out, sign up, update · plataformatec/devise Wiki