# 機能設計書 3-Active Record

## 概要

本ドキュメントは、Ruby on RailsフレームワークにおけるActive Recordの機能設計を記述する。Active Recordは、オブジェクト関係マッパー（ORM）フレームワークとして、データベーステーブルをRubyクラスにマッピングし、永続的なドメインモデルを構築するためのコアコンポーネントである。

### 本機能の処理概要

Active Recordは、Martin Fowlerの「Active Record」パターンを実装したORMであり、データベース操作をオブジェクト指向的なインターフェースで提供する。

**業務上の目的・背景**：Webアプリケーションにおいて、データベースとの連携は不可欠であるが、SQL文を直接記述することは生産性の低下やセキュリティリスクにつながる。Active Recordは、データベース操作をRubyオブジェクトのメソッド呼び出しとして抽象化し、開発者がSQL文を意識せずにデータ操作を行えるようにする。また、マイグレーション機能によりデータベーススキーマのバージョン管理が可能となり、チーム開発における環境の一貫性を保証する。

**機能の利用シーン**：
- データベースからのレコード検索・取得（CRUD操作）
- レコードの作成・更新・削除
- テーブル間の関連付け（アソシエーション）の定義と操作
- データのバリデーション
- データベーススキーマのマイグレーション
- トランザクション管理
- クエリの最適化（Eager Loading等）

**主要な処理内容**：
1. モデルクラスとデータベーステーブルのマッピング
2. 属性のアクセサメソッド自動生成
3. CRUD操作（Create、Read、Update、Delete）
4. アソシエーション（belongs_to、has_many、has_one等）
5. バリデーション（validates、validate_presence_of等）
6. コールバック（before_save、after_create等）
7. マイグレーションによるスキーマ管理
8. クエリインターフェース（where、order、joins等）
9. トランザクション管理（transaction、with_lock）
10. 暗号化属性（encrypts）

**関連システム・外部連携**：
- PostgreSQL、MySQL、SQLite3等のRDBMS
- Active Model: バリデーション・コールバック基盤
- Arel: SQLクエリビルダー
- 各種データベースアダプター

**権限による制御**：Active Recordは直接的な認可制御を提供しないが、データベースレベルの権限（SELECT、INSERT、UPDATE、DELETE）がクエリ実行に影響する。アプリケーションレベルの認可はPundit等のgemで別途実装される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 14 | 無効なステートメント画面 | 補助機能 | SQL文エラー情報の表示 |
| 17 | 受信メール一覧画面 | 補助機能 | InboundEmailモデルのクエリ実行（order created_at desc） |

## 機能種別

ORM / データ永続化 / クエリビルダー

## 入力仕様

### 入力パラメータ

#### モデル定義

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| table_name | String | No | テーブル名（省略時はクラス名から推論） | 有効なテーブル名 |
| primary_key | String/Symbol | No | 主キーカラム名（デフォルト: id） | - |
| inheritance_column | String | No | STIカラム名（デフォルト: type） | - |

#### find系メソッド

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | Integer/Array | Yes | 検索対象のID | 存在するIDであること |

#### where系メソッド

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| conditions | String/Array/Hash | Yes | 検索条件 | SQLインジェクション対策済み |

### 入力データソース

- アプリケーションコードからのメソッド呼び出し
- マイグレーションファイル
- シードファイル（db/seeds.rb）
- データベース接続設定（config/database.yml）

## 出力仕様

### 出力データ

#### find/where

| 項目名 | 型 | 説明 |
|--------|-----|------|
| record | ActiveRecord::Base | 単一レコード |
| records | ActiveRecord::Relation | レコードのコレクション |

#### create/update

| 項目名 | 型 | 説明 |
|--------|-----|------|
| success | Boolean | 操作の成功/失敗 |
| errors | ActiveModel::Errors | バリデーションエラー |

### 出力先

- データベーステーブル
- ActiveRecord::Relation（クエリ結果）
- ActiveRecord::Base インスタンス

## 処理フロー

### 処理シーケンス（レコード作成）

```
1. new または create 呼び出し
   └─ インスタンス生成、属性設定
2. before_validation コールバック実行
   └─ バリデーション前の前処理
3. バリデーション実行
   └─ validates で定義されたルールを検証
4. after_validation コールバック実行
   └─ バリデーション後の処理
5. before_save コールバック実行
   └─ 保存前の共通処理
6. before_create コールバック実行
   └─ 新規作成前の処理
7. INSERT文実行
   └─ データベースへの書き込み
8. after_create コールバック実行
   └─ 新規作成後の処理
9. after_save コールバック実行
   └─ 保存後の共通処理
10. after_commit コールバック実行
    └─ トランザクションコミット後の処理
```

### フローチャート

```mermaid
flowchart TD
    A[モデルインスタンス生成] --> B{バリデーション}
    B -->|Valid| C[before_save コールバック]
    B -->|Invalid| D[エラー返却]
    C --> E{新規レコード?}
    E -->|Yes| F[before_create]
    E -->|No| G[before_update]
    F --> H[INSERT実行]
    G --> I[UPDATE実行]
    H --> J[after_create]
    I --> K[after_update]
    J --> L[after_save]
    K --> L
    L --> M[after_commit]
    M --> N[完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 主キー自動採番 | id カラムはデフォルトで自動採番される | INSERT時 |
| BR-002 | タイムスタンプ自動更新 | created_at/updated_at が自動更新される | CREATE/UPDATE時 |
| BR-003 | 楽観的ロック | lock_version カラムがある場合、更新時にバージョンチェック | UPDATE時 |
| BR-004 | belongs_to 必須 | Rails 5以降、belongs_to は optional: true 指定がなければ必須 | バリデーション時 |
| BR-005 | 安全なクエリ | プレースホルダを使用してSQLインジェクションを防止 | クエリ実行時 |

### 計算ロジック

**楽観的ロックバージョン管理**：
```ruby
# UPDATE時
lock_version = current_version + 1
# WHERE句に現在のバージョンを含め、一致しなければStaleObjectError
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| find | 任意 | SELECT | 主キーによるレコード取得 |
| where | 任意 | SELECT | 条件指定によるレコード取得 |
| create | 任意 | INSERT | 新規レコード作成 |
| update | 任意 | UPDATE | 既存レコード更新 |
| destroy | 任意 | DELETE | レコード削除 |
| migrate | schema_migrations | INSERT/DELETE | マイグレーションバージョン管理 |

### テーブル別操作詳細

#### schema_migrations テーブル

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | version | マイグレーションのタイムスタンプ | db:migrate 実行時 |
| DELETE | version | ロールバック対象のタイムスタンプ | db:rollback 実行時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ActiveRecord::RecordNotFound | 指定IDのレコードが存在しない | findの代わりにfind_byを使用 |
| - | ActiveRecord::RecordInvalid | バリデーションエラー時にsave!を使用 | saveを使用しエラーハンドリング |
| - | ActiveRecord::StaleObjectError | 楽観的ロックの競合 | リトライまたはユーザーへ通知 |
| - | ActiveRecord::StatementInvalid | 不正なSQL文 | SQL構文・カラム名を確認 |
| - | ActiveRecord::ConnectionNotEstablished | DB接続失敗 | database.yml設定を確認 |

### リトライ仕様

デッドロック発生時、ActiveRecord::Deadlockedが発生する。アプリケーション層でのリトライ実装が必要。

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

```ruby
ActiveRecord::Base.transaction do
  # トランザクション内の処理
  # 例外発生時は自動的にROLLBACK
end
```

- ネストしたトランザクションはSAVEPOINTで実装
- `requires_new: true` で新しいサブトランザクションを開始
- コールバックは after_commit / after_rollback でトランザクション完了後に実行

## パフォーマンス要件

- N+1クエリ問題を避けるため、includes/preload/eager_loadを使用
- 大量レコード処理にはfind_each/find_in_batchesを使用
- インデックス最適化によるクエリ高速化

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

- SQLインジェクション対策：プレースホルダ使用
- マスアサインメント対策：Strong Parameters（Action Controllerと連携）
- 属性暗号化：encrypts メソッドによる機密データの暗号化
- protected_environments による本番環境での破壊的操作防止

## 備考

Active Recordは `activerecord` gem として提供される。関連付け、バリデーション、マイグレーション機能を含む。

---

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

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

### 推奨読解順序

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

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

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

**読解のコツ**: `autoload` 定義を見て、Active Recordがどのようなサブモジュールで構成されているか把握する。

**主要処理フロー**:
- **41-93行目**: ActiveRecordモジュールの定義と各機能のautoload
- **95-124行目**: eager_autoloadブロック。起動時にロードされるモジュール
- **184-186行目**: disable_prepared_statements設定

#### Step 2: エントリーポイントを理解する

ActiveRecord::Baseクラスの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | base.rb | `activerecord/lib/active_record/base.rb` | ActiveRecord::Baseの基本構造とドキュメント |

**主要処理フロー**:
- **15-47行目**: Active Recordの基本概念説明（オブジェクトとテーブルのマッピング）
- **28-46行目**: オブジェクト作成方法（ハッシュ、ブロック）
- **48-99行目**: クエリ条件の指定方法

#### Step 3: アソシエーションを理解する

テーブル間の関連付けを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | associations.rb | `activerecord/lib/active_record/associations.rb` | アソシエーションモジュール |

#### Step 4: バリデーションを理解する

データの妥当性検証を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | validations.rb | `activerecord/lib/active_record/validations.rb` | バリデーションの実装 |

#### Step 5: クエリインターフェースを理解する

Relationとクエリメソッドを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | relation.rb | `activerecord/lib/active_record/relation.rb` | Relationクラスの基本 |
| 5-2 | query_methods.rb | `activerecord/lib/active_record/relation/query_methods.rb` | where、order等のクエリメソッド |

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

```
ActiveRecord::Base
    │
    ├─ Core (include)
    │      └─ 基本的なモデル機能
    │
    ├─ Persistence (include)
    │      ├─ save / save!
    │      ├─ create / create!
    │      ├─ update / update!
    │      └─ destroy / destroy!
    │
    ├─ Querying (extend)
    │      ├─ find / find_by
    │      ├─ where / order
    │      └─ Relation へ委譲
    │
    ├─ Associations (include)
    │      ├─ belongs_to
    │      ├─ has_many
    │      ├─ has_one
    │      └─ has_and_belongs_to_many
    │
    ├─ Validations (include)
    │      ├─ validates
    │      └─ validate
    │
    ├─ Callbacks (include)
    │      ├─ before_save
    │      ├─ after_save
    │      └─ etc.
    │
    └─ ConnectionHandling (extend)
           ├─ establish_connection
           └─ connection
```

### データフロー図

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

Ruby コード ───▶ ActiveRecord::Base ───▶ Arel AST ───▶ SQL文
  User.where(name: "foo")     │                              │
                              ▼                              ▼
                         Relation                      データベース
                              │                              │
                              ▼                              ▼
                       クエリ実行 ◀──────────────────── 結果セット
                              │
                              ▼
                    ActiveRecord インスタンス群
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| active_record.rb | `activerecord/lib/active_record.rb` | ソース | メインエントリーポイント |
| base.rb | `activerecord/lib/active_record/base.rb` | ソース | モデル基底クラス |
| core.rb | `activerecord/lib/active_record/core.rb` | ソース | コア機能 |
| persistence.rb | `activerecord/lib/active_record/persistence.rb` | ソース | 永続化機能（CRUD） |
| querying.rb | `activerecord/lib/active_record/querying.rb` | ソース | クエリインターフェース |
| relation.rb | `activerecord/lib/active_record/relation.rb` | ソース | Relationクラス |
| query_methods.rb | `activerecord/lib/active_record/relation/query_methods.rb` | ソース | クエリメソッド |
| associations.rb | `activerecord/lib/active_record/associations.rb` | ソース | アソシエーション |
| validations.rb | `activerecord/lib/active_record/validations.rb` | ソース | バリデーション |
| callbacks.rb | `activerecord/lib/active_record/callbacks.rb` | ソース | コールバック |
| migration.rb | `activerecord/lib/active_record/migration.rb` | ソース | マイグレーション |
| transactions.rb | `activerecord/lib/active_record/transactions.rb` | ソース | トランザクション |
| encryption.rb | `activerecord/lib/active_record/encryption.rb` | ソース | 属性暗号化 |
