Claude
Skills
Sign in
Back

rails-delegated-roles

Included with Lifetime
$97 forever

Use delegated_type to implement role delegation in Rails applications, with separate models and tables for each role.

General

What this skill does


# Rails Delegated Roles

Use `delegated_type` when roles have their own data, associations, or validations. If roles are just permission flags, use a simpler approach.

## The Problem

A "Blob" model absorbs role-specific logic, forcing optional associations and conditional validations:

```ruby
# Avoid: associations must be optional, validations need guards
class User < ApplicationRecord
  belongs_to :classroom, optional: true  # Only students have classrooms
  validates :grade_level, presence: true, if: :student?
end
```

## The Solution

### 1. Role model with delegated_type

```ruby
class Role < ApplicationRecord
  belongs_to :user
  delegated_type :assignable, types: %w[Administrator Tutor Student]
end
```

This generates scopes (`Role.students`) and predicates (`role.student?`).

### 2. Role-specific models

Each role owns its data with required associations:

```ruby
class Student < ApplicationRecord
  has_one :role, as: :assignable
  belongs_to :classroom  # Required, not optional
  validates :grade_level, presence: true
end
```

### 3. Auto-generate User methods

```ruby
module RoleHelpers
  extend ActiveSupport::Concern

  included do
    has_many :roles

    Role.assignable_types.each do |type|
      scope_name = type.tableize.tr('/', '_')
      singular = scope_name.singularize

      define_method("#{singular}?") { roles.public_send(scope_name).exists? }
      define_method(singular) { roles.public_send(scope_name).first&.assignable }
    end
  end
end
```

### 4. Migration

```ruby
create_table :roles do |t|
  t.references :user, null: false, foreign_key: true
  t.references :assignable, polymorphic: true, null: false
  t.timestamps
end
add_index :roles, %i[user_id assignable_type], unique: true
```

Each role type gets its own table with role-specific columns.

## Trade-offs

Role assignment becomes deliberate (create records, not toggle checkboxes). This aids auditability but increases complexity.

Related in General