はじめに
この記事では、Ruby on Railsの人気認証ライブラリであるDeviseを使用して、異なるユーザーモデル間でのアクセス制御を実装する方法を解説します。特に、Company
モデルがログインしている状態から、ログインせずに Staff
モデルを編集する方法に焦点を当てます。
実装の試みと課題
初めに、Staffs::RegistrationsController
を使ったアプローチを試みましたが、どうしてもログイン画面に遷移してしまい原因がわからないという問題に直面しました。
最終的な解決策
この問題を解決するために、StaffsController
を利用して、Company
モデルが Staff
モデルのデータを安全に編集できるようにしました。以下はその具体的な実装です。
1. コントローラの設定
class StaffsController < ApplicationController
before_action :authenticate_company_or_staff!, only: %i(edit update destroy)
before_action :set_staff, only: %i[show edit update]
def edit
end
def update
if @staff.update(staff_params)
redirect_to staff_path(@staff), notice: 'スタッフ情報が更新されました。'
else
render :edit
end
end
private
def set_staff
@staff = Staff.find(params[:id])
end
# 以下で認証確認
def authenticate_company_or_staff!
unless company_signed_in? || staff_signed_in?
redirect_to new_company_session_path, alert: 'ログインが必要です。'
end
end
def staff_params
params.require(:staff).permit(:company_id,
:name,
:email,
:position,
:telephone,
:postal_code,
:prefecture,
:city,
:street_address,
:description,
:password,
:password_confirmation,
:current_password,
service_ids: [])
end
def parse_date
@date = params[:date].present? ? Date.parse(params[:date]) : Date.today # パラメータが存在する場合のみDateオブジェクトを作成
end
end
2. ビューファイルの編集フォーム
<div class="container mt-4">
<h2>スタッフ更新</h2>
<%= render 'form', staff: @staff %>
</div>
3. フォームの部分テンプレート
フォームは、_form.html.erb
に分けて、スタッフの情報を更新できるようにフィールドを配置しました。このフォームは、current_company
が存在する場合に限り、会社IDを隠しフィールドとして送信します。
知見
- Deviseで異なるモデル間のアクセス制御を行う際には、RegistrationControllerではうまく制御できず、ログイン画面に遷移させられることがある。
- 上記の場合、自身でコントローラを作成して制御することで対応可能(
StaffsController
など) - CanCanCanを使用することで、誰がどのリソースにアクセスできるかを細かく制御可能。