概要
この記事では、RailsアプリケーションでDeviseとCanCanCanを使用して、Company
と Staff
という二つのユーザーモデルを効果的に管理する方法を紹介します。
特に、Company
モデルでログインしている状態で Staff
モデルのデータを編集できるようにする際に生じた以下のエラーの解消法を詳しく解説します。
Completed 401 Unauthorized in 0ms (ActiveRecord: 0.0ms | Allocations: 209)
※ブラウザでリンクを選択後、アクションに遷移する前に上記のエラーが生じたため、deviseの認証関連が原因ではないかとあたりをつけました。
1. 導入
本記事では、企業とその従業員をそれぞれ Company
と Staff
モデルで管理するシナリオを想定しています。各モデルはDeviseによって認証が行われ、CanCanCanでアクセス権限が管理されます。この設定を通じて、モデルごとの認証と権限のカスタマイズ方法を学びます。
2. 環境設定
このチュートリアルを始める前に、以下のGemがインストールされていることを確認してください。
gem 'rails', '~> 6.0.0'
gem 'devise'
gem 'cancancan', '~> 3.0'
これらのGemをインストールした後、DeviseとCanCanCanの初期設定を行います。
rails generate devise:install
rails generate cancan:ability
3. Deviseのセットアップ
Company
と Staff
モデルにDeviseを適用します。まずはモデルを生成し、Deviseのモジュールを追加します。
rails generate devise Company
rails generate devise Staff
次に、config/routes.rb
でDeviseのルーティングを設定します。
devise_for :companies
devise_for :staffs
4. CanCanCanの権限設定
Ability
クラスで、Company
が Staff
のデータを編集できるように権限を設定します。
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
if user.is_a?(Company)
can :manage, Staff, company_id: user.id
end
# その他の権限設定...
end
end
5. エラー発生
上記の概要で述べたエラーがここで生じました。
Completed 401 Unauthorized in 0ms (ActiveRecord: 0.0ms | Allocations: 209)
処理開始後にbinding.pryで処理を停止させることができなかったことと、Rails.logger.debugでログ取得をしようとしても何も情報を得られなかったため
- controllerのcontrollerのアクション以前の処理
- CanCanCan関連
- Devise関連
のエラーを疑いました。
6. 対策
Staffs::RegistrationsController
をカスタマイズして解決しました。
class Staffs::RegistrationsController < Devise::RegistrationsController
before_action :set_staff, only: %i(edit update destroy)
# ↓以下のauthenticate_staff!を追記(protected以下でオーバーライドしたものを使用する)
before_action :authenticate_staff!, only: %i(edit update destroy)
load_and_authorize_resource :class => 'Staff', except: %i(create)
before_action :configure_permitted_parameters, if: :devise_controller?
def edit
@staff = Staff.find(params[:id])
end
protected
# 以下でauthenticate_staff!をオーバーライド
def authenticate_staff!(opts = {})
@staff = Staff.find(params[:id])
unless staff_signed_in? || (company_signed_in? && @staff.company_id == current_company.id)
redirect_to new_company_session_path, alert: 'アクセス権限がありません。'
end
end
def set_staff
if resource.present?
@staff = Staff.find(resource.id)
end
end
# その他の設定...
end
7. まとめ
DeviseとCanCanCanを用いて複数のモデルに対する認証と権限管理を行う方法を学びました。この技術は、大規模なRailsアプリケーションでのアクセス制御に非常に有効です。