[Rails]Omniauthで戻り先URLを指定する
Ruby2.0, Rails4.1で確認
先日、 RailsでOmniauthを使ってTwitterログインする方法をまとめました。
その後、色々改良していたところ、ログイン後に必ずroot_pathにリダイレクトさせるのではなく、URLパラメータに戻り先URLを入れて動的にログイン後の遷移を変更したくなりました。
そこで調べてみたところ、 こちらの記事にやり方が紹介されていました。
Omniauthを使っている場合は、URLにoriginパラメータを指定すればうまいことやってくれるそうです。
お手軽ですね。
前回のSessionContrllerを改良します。
- 前回のSessionController
# app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def callback
auth = request.env['omniauth.auth']
user = User.find_by_provider_and_uid(auth['provider'], auth['uid']) || User.create_with_omniauth(auth)
session[:user_id] = user.id
redirect_to root_path
end
def destroy
session[:user_id] = nil
redirect_to root_path
end
end
- これをこう
# app/controllers/sessions_controller.rb
class SessionsController < BaseController
def callback
auth = request.env['omniauth.auth']
# 複数のサービスに対応させるために前回から少し変更
session[auth['provider'].to_sym] = {
:user_id => auth['uid'],
:name => auth['info']['name'],
:oauth_token => auth['credentials']['token'],
:oauth_token_secret => auth['credentials']['secret']
}
# originが指定されており、同一ドメインの場合は指定の戻り先にリダイレクト
redirect_to back_to || root_path
end
def destroy
reset_session
redirect_to root_path
end
private
def back_to
if request.env['omniauth.origin'].presence && back_to = CGI.unescape(request.env['omniauth.origin'].to_s)
uri = URI.parse(back_to)
return back_to if uri.relative? || uri.host == request.host
end
nil
rescue
nil
end
end
これで、ログイン時(/auth/twitterや/auth/facebookアクセス時)に?origin=/hogeが指定されていたら、ログイン後に/hogeにリダイレクトされるようになります。
before_actionで認証が必要なページにアクセスした場合もoriginを渡せるようにしておきましょう。
今回はfacebookの場合のサンプルを載せておきます。
loginとwallというURLを追加してみます。
loginはfacebook認証不要、wallはfacebook認証が必要なページです。
- routing
# config/routes.rb
get "login", :to => "sample#login", :as => :login
get "wall", :to => "sample#wall", :as => :wall
- SampleController
# app/controllers/sample_controller.rb
class SampleController < BaseController
# facebook認証チェック
before_action :facebook_login_required, only: [:wall]
# loginはfacebook認証が不要
def login
end
# wallはfacebook認証が必要
def wall
end
end
- loginテンプレートにwallへのリンクを表示
# app/views/sample/login.html.erb
<%= link_to 'facebook_login', wall_path(:origin => '/wall') %>
- BaseControllerにfacebook認証チェックを追加
# app/controllers/base_controller.rb
class BaseController < ApplicationController
# facebook未ログイン時に facebook_oauth_path へリダイレクトする
def facebook_login_required
if !facebook_logged_in?
# originが含まれている場合はパラメータに追加
if params['origin'].blank?
redirect_to '/auth/facebook'
else
redirect_to '/auth/facebook?origin=' + params['origin']
end
end
end
private
def facebook_logged_in?
(session[:facebook] && session[:facebook][:user_id]) ? true : false
end
end
facebook_login_requiredの部分で、受け取ったoriginパラメータを渡すようにすることでbefore_action経由でもうまく戻り先URLに戻れるようになります。