PIYO - Tech & Life -

RailsでDeviseを使ったときのログイン周りの画面遷移

Devise Rails

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

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

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

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

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

# application_controller.rb
class ApplicationController < ActionController::Base
private
  def sign_in_required
    redirect_to new_user_session_url unless user_signed_in?
  end
end

# hoge_controller.rb
class HogeController < ApplicationController
  before_action :sign_in_required
  def index
    # ...
  end

  def ...
end	

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

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

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

class ApplicationController < ActionController::Base
  before_action :store_location

  private

  def sign_in_required
    redirect_to new_user_session_url unless user_signed_in?
  end

  def store_location
    return unless request.get? 
    if (request.path != "/users/sign_in" &&
        request.path != "/users/sign_up" &&
        request.path != "/users/password/new" &&
        request.path != "/users/sign_out" &&
        !request.xhr?)
      session[:previous_url] = request.fullpath 
    end
  end

  def after_sign_in_path_for(resource)
    session[:previous_url] || root_path
  end  

end

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