💬

DelegatedTypesで複数のユーザー権限を管理する

に公開

DelegatedTypesを使って、管理者と顧客の2つのユーザー情報を管理する。

DelegatedTypesで管理者と顧客で異なるユーザー属性情報を個別のテーブル情報を作成することで管理する。
例えばテーブルはUser、Administrator、Customerの3テーブルとなる。

Userテーブル

id email_address userable_type user_id
1 admin-1@example.com Administrator 1
2 customer-1@example.com Customer 2

Administratorテーブル

id deperatment employee_code
1 sales 19

Customerテーブル

id birth address
1 2024-12-31 Tokyo

DelegatedTypesをユーザーモデルに適用する

railsアプリーケーションを作成する。

gem exec rails new app --devcontainer
bin/rails g authentication

作成されたユーザーテーブルをスーパークラスとしてDelegatedTypesを属性情報を指定する。

bin/rails generate migration AddUserableToUser userable_type:string userable_id:integer

DelegatedTypesで使うAdministratorとCustomerを作成する

bin/rails g model Administrator department:string employee_code:string
bin/rails g model Customer birth:date address:string

UserクラスでDelegatedTypesを宣言する

class User < ApplicationRecord
  has_secure_password
  has_many :sessions, dependent: :destroy

  normalizes :email_address, with: ->(e) { e.strip.downcase }

  delegated_type :userable, types: %w[ Administrator Customer ], dependent: :destroy
end

委譲クラスとして、AdministratorCustomerが含まれる。

rails consoleからユーザーを作成する

# Customerの作成
User.create!(email_address: "customer-1@example.com", password: "password!", userable: Customer.new(birth: "2024-12-31", address: "Tokyo"))
# Adminの作成
User.create!(email_address: "admin-1@example.com", password: "password!", userable: Administrator.new(department: "sales", employee_code: "19"))

# DelegateTypeによりユーザー判定可能
User.find_by(email_address: "customer-1@example.com").customer?
=> true
User.find_by(email_address: "admin-1@example.com").administrator?
=> true

ユーザーログイン

CustomerとAdministrator用のcontrollerを作成する。

bin/rails g controller admin/home index
bin/rails g controller customer/home index

ユーザーがCustomerかAdministratorかにより画面制御を行う。

class Customer::HomeController < ApplicationController
  before_action :require_customer_access

  def index
  end

  private

  def require_customer_access
    raise ActionController::RoutingError, "Not Found" unless Current.user.customer?
  end
end
class Admin::HomeController < ApplicationController
  before_action :require_admin_access

  def index
  end

  private

  def require_admin_access
    raise ActionController::RoutingError, "Not Found" unless Current.user.administrator?
  end
end

また、ログイン時に遷移先の切り替えが必要。

module Authentication
    def after_authentication_url
      session.delete(:return_to_after_authenticating)

      if Current.user.administrator?
        admin_root_url
      elsif Current.user.customer?
        customer_root_url
      else
        root_url
      end
    end
end

参考

https://acuments.com/active-record-delegated-type.html
「3. Multiple tables with an association」よりは「4. Active Record delegated_type」のほうが、DelegatedTypesがIFを提供してくれるためより実装がシンプル。

Discussion