# 機能設計書 4-Active Model

## 概要

本ドキュメントは、Ruby on RailsフレームワークにおけるActive Modelの機能設計を記述する。Active Modelは、モデリングフレームワーク構築のためのツールキットであり、属性・コールバック・バリデーション・シリアライゼーション・国際化のサポートを提供する。

### 本機能の処理概要

Active Modelは、Active Recordの基盤となる機能を提供するモジュール群であり、データベースに依存しないモデルクラスの構築を可能にする。

**業務上の目的・背景**：Webアプリケーションでは、データベースに永続化しないオブジェクト（フォームオブジェクト、サービスオブジェクト等）でも、バリデーションやコールバック等のモデル機能が必要となることが多い。Active Modelは、これらの機能をActive Recordから分離し、任意のRubyクラスに組み込めるようにすることで、柔軟なモデル設計を可能にする。また、Action View/Action Controllerとの連携規約を提供し、フォームビルダーやルーティングとシームレスに統合できる。

**機能の利用シーン**：
- フォームオブジェクトの作成（複数モデルをまたぐフォーム処理）
- APIレスポンス用のシリアライゼーション
- バリデーションロジックの実装
- コールバックによるライフサイクル管理
- 属性の型変換と正規化
- 変更追跡（Dirty tracking）

**主要な処理内容**：
1. Attributes による属性定義と型変換
2. Validations によるデータ妥当性検証
3. Callbacks によるライフサイクルフック
4. Serialization によるJSON/XML変換
5. Conversion によるルーティング・フォームとの統合
6. Dirty による属性変更追跡
7. SecurePassword によるパスワードハッシュ化
8. Model/API による最小限のモデルインターフェース

**関連システム・外部連携**：
- bcrypt gem: SecurePasswordで使用
- argon2 gem: SecurePasswordで使用（オプション）
- I18n: 国際化サポート

**権限による制御**：Active Modelは直接的な認可制御を提供しない。SecurePasswordによるパスワードハッシュ化は認証の基盤として使用される。

## 関連画面

Active Modelは基盤ライブラリであり、特定の画面には直接対応しない。フォームオブジェクトやバリデーションとしてすべての画面で間接的に利用される。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 全画面共通 | 基盤機能 | フォームバリデーション、モデル変換 |

## 機能種別

モデリングフレームワーク / バリデーション / シリアライゼーション

## 入力仕様

### 入力パラメータ

#### attribute 定義

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | Symbol | Yes | 属性名 | 有効な識別子 |
| type | Symbol/Type | No | 属性の型 | 登録済みの型 |
| default | Object/Proc | No | デフォルト値 | - |

#### validates 定義

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| attribute | Symbol | Yes | 検証対象の属性名 | - |
| validators | Hash | Yes | バリデーションオプション | presence/length/format等 |

#### has_secure_password

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| attribute | Symbol | No | パスワード属性名（デフォルト: password） | - |
| validations | Boolean | No | バリデーションの有無 | - |
| algorithm | Symbol | No | ハッシュアルゴリズム（:bcrypt/:argon2id） | - |

### 入力データソース

- アプリケーションコードからのメソッド呼び出し
- フォームパラメータ（Action Controllerから）
- APIリクエストボディ

## 出力仕様

### 出力データ

#### valid?

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | Boolean | バリデーション結果 |

#### errors

| 項目名 | 型 | 説明 |
|--------|-----|------|
| errors | ActiveModel::Errors | エラーメッセージコレクション |

#### as_json

| 項目名 | 型 | 説明 |
|--------|-----|------|
| json | Hash | シリアライズされたオブジェクト |

### 出力先

- メモリ上のオブジェクト
- JSONレスポンス
- エラーメッセージ表示

## 処理フロー

### 処理シーケンス（バリデーション）

```
1. valid? 呼び出し
   └─ バリデーション開始
2. before_validation コールバック実行
   └─ バリデーション前の前処理
3. 各バリデータの実行
   └─ validates で定義されたルールを順次検証
4. after_validation コールバック実行
   └─ バリデーション後の処理
5. 結果返却
   └─ true/false とエラー情報
```

### フローチャート

```mermaid
flowchart TD
    A[valid? 呼び出し] --> B[before_validation]
    B --> C{各バリデータ実行}
    C --> D{エラーあり?}
    D -->|Yes| E[errorsに追加]
    D -->|No| F[次のバリデータ]
    E --> F
    F --> G{全バリデータ完了?}
    G -->|No| C
    G -->|Yes| H[after_validation]
    H --> I{errors.empty?}
    I -->|Yes| J[true を返却]
    I -->|No| K[false を返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | バリデーション順序 | バリデータは定義順に実行される | valid? 呼び出し時 |
| BR-002 | エラー蓄積 | バリデーションエラーは errors に蓄積される | バリデーション失敗時 |
| BR-003 | Dirty追跡 | changed? は属性が変更されたかを返す | 属性変更後 |
| BR-004 | SecurePassword | パスワードはbcryptまたはargon2でハッシュ化 | 保存時 |

### 計算ロジック

**パスワードハッシュ化（bcrypt）**：
```ruby
BCrypt::Password.create(password, cost: BCrypt::Engine.cost)
```

**パスワード検証**：
```ruby
BCrypt::Password.new(password_digest) == unencrypted_password
```

## データベース操作仕様

Active Model自体は直接データベース操作を行わない。

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | Active Model自体はDB操作を行わない |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ActiveModel::ValidationError | バリデーションコンテキストでのエラー | エラーメッセージを確認 |
| - | ActiveModel::StrictValidationFailed | strict: trueのバリデーションが失敗 | バリデーション条件を見直し |
| - | ActiveModel::UnknownAttributeError | 未定義の属性への代入 | 属性定義を確認 |
| - | ActiveModel::RangeError | 数値が範囲外 | 入力値を検証 |

### リトライ仕様

バリデーションエラー時のリトライは行われない。エラー内容を修正して再度valid?を呼び出す。

## トランザクション仕様

Active Modelはトランザクション管理を直接行わない。

## パフォーマンス要件

- バリデーション実行: ミリ秒オーダー
- パスワードハッシュ化: cost設定に依存（セキュリティとのトレードオフ）

## セキュリティ考慮事項

- SecurePasswordはbcrypt/argon2によるハッシュ化を提供
- パスワードは平文で保存されない
- ForbiddenAttributesProtectionによるマスアサインメント対策

## 備考

Active Modelは `activemodel` gem として提供される。Active Recordの基盤となる機能を提供する。

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

Active Modelのモジュール構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | active_model.rb | `activemodel/lib/active_model.rb` | モジュール定義とautoload一覧 |

**読解のコツ**: 各モジュールの役割（Attributes、Validations、Callbacks等）を把握する。

**主要処理フロー**:
- **32-58行目**: ActiveModelモジュールの定義とautoload
- **60-67行目**: eager_autoloadブロック（Errors等）
- **77-80行目**: eager_load!メソッド

#### Step 2: Modelモジュールを理解する

最小限のモデルインターフェースを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | model.rb | `activemodel/lib/active_model/model.rb` | Modelモジュールの実装 |

#### Step 3: Validationsを理解する

バリデーション機構を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | validations.rb | `activemodel/lib/active_model/validations.rb` | バリデーションモジュール |

#### Step 4: Attributesを理解する

属性定義と型変換を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | attributes.rb | `activemodel/lib/active_model/attributes.rb` | 属性モジュール |

#### Step 5: SecurePasswordを理解する

パスワードハッシュ化を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | secure_password.rb | `activemodel/lib/active_model/secure_password.rb` | SecurePasswordモジュール |

### プログラム呼び出し階層図

```
ActiveModel::Model (include)
    │
    ├─ ActiveModel::API (include)
    │      ├─ ActiveModel::AttributeAssignment
    │      ├─ ActiveModel::Validations
    │      └─ ActiveModel::Conversion
    │
    ├─ ActiveModel::Attributes (include)
    │      └─ attribute メソッド
    │
    ├─ ActiveModel::Callbacks (include)
    │      └─ before/after/around コールバック
    │
    ├─ ActiveModel::Dirty (include)
    │      └─ 変更追跡
    │
    └─ ActiveModel::SecurePassword (include)
           └─ has_secure_password
```

### データフロー図

```
[入力]                    [処理]                           [出力]

フォームパラメータ ───▶ AttributeAssignment ───▶ 属性設定済みオブジェクト
       │                        │
       ▼                        ▼
検証対象オブジェクト ───▶ Validations ───▶ true/false + errors
       │                        │
       │                        ├─ PresenceValidator
       │                        ├─ LengthValidator
       │                        └─ FormatValidator
       │
       ▼
オブジェクト ───▶ Serialization ───▶ JSON/Hash
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| active_model.rb | `activemodel/lib/active_model.rb` | ソース | メインエントリーポイント |
| model.rb | `activemodel/lib/active_model/model.rb` | ソース | 最小限のモデルインターフェース |
| api.rb | `activemodel/lib/active_model/api.rb` | ソース | APIモデルインターフェース |
| attributes.rb | `activemodel/lib/active_model/attributes.rb` | ソース | 属性定義 |
| validations.rb | `activemodel/lib/active_model/validations.rb` | ソース | バリデーション |
| callbacks.rb | `activemodel/lib/active_model/callbacks.rb` | ソース | コールバック |
| dirty.rb | `activemodel/lib/active_model/dirty.rb` | ソース | 変更追跡 |
| serialization.rb | `activemodel/lib/active_model/serialization.rb` | ソース | シリアライゼーション |
| conversion.rb | `activemodel/lib/active_model/conversion.rb` | ソース | 型変換 |
| errors.rb | `activemodel/lib/active_model/errors.rb` | ソース | エラーコレクション |
| secure_password.rb | `activemodel/lib/active_model/secure_password.rb` | ソース | パスワードハッシュ化 |
| translation.rb | `activemodel/lib/active_model/translation.rb` | ソース | I18n統合 |
