はじめに
例としてECサイトなどで、deviseをつかってUserモデルとStoreモデルを作成した場合、デフォルトではそれぞれのモデルで同時にログインや新規登録が可能です。今回はそれを修正したいと思います。
コントローラーを表示する
$
rails generate devise:controllers users
rails generate devise:controllers admins
ルーティング
devise_for :users, controllers: { sessions: 'users/sessions', registrations: 'users/registrations'}
devise_for :stores, controllers: { sessions: 'stores/sessions', registrations: 'stores/registrations'}
これを忘れるとコントローラー内でオーバーライドした内容が反映されないので注意しましょう。
モジュールの作成
module Accessible
extend ActiveSupport::Concern
included do
prepend_before_action :check_user
end
protected
def check_user
if current_store
flash[:notice] = '店舗として既にログインしています。'
redirect_to(current_store) and return
elsif current_user
flash[:notice] = 'ユーザーとして既にログインしています。'
redirect_to(root_path) and return
end
end
end
check_userメソッドではそれぞれのモデルでログインしている場合はリダイレクトする処理を行っています。
これをコールバックに登録するのですが、理由は後述しますがbefore_actionではなくprepend_before_actionに登録しています。
モジュールの読み込み
class Users::RegistrationsController < Devise::RegistrationsController
include Accessible
skip_before_action :check_user, except: [:new, :create]
.
.
.
end
ここでは、自分のアカウント情報にアクセスして編集する目的と、edit,update,destroyアクションはdeviseのデフォルトの機能によりログインしているアカウントしかアクセス出来ないという理由でchek_userメソッドを呼び出していません。
class Stores::SessionsController < Devise::SessionsController
include Accessible
skip_before_action :check_user, only: :destroy
.
.
.
end
ログアウトする必要があるのでdestroyアクションには適用していません。
これで完成です。
before_actionではなくprepend_before_actionにコールバック関数を登録している理由
devise/app/controllers/devise/sessions_controller.rb
より、
.
.
prepend_before_action :require_no_authentication, only: [:new, :create]
prepend_before_action :allow_params_authentication!, only: :create
.
.
.
# POST /resource/sign_in
def create
self.resource = warden.authenticate!(auth_options)
set_flash_message!(:notice, :signed_in)
sign_in(resource_name, resource)
yield resource if block_given?
respond_with resource, location: after_sign_in_path_for(resource)
end
createアクションにはprepend_before_actionが登録されており、それらのメソッドが実行されると
current_userがtrueを返してしまいます。よってモジュール内で指定したcheck_userメソッドはprepend_before_actionに登録する必要があります。
参考
最後に
:require_no_authenticationメソッドや:allow_params_authentication!の中身をちゃんと理解していないので理解したいと思います。
何か間違った点や理解が怪しそうなところがあれば是非ご教授ください!