# 機能設計書 14-Action Text

## 概要

本ドキュメントは、Ruby on Railsフレームワークにおけるリッチテキストフレームワーク「Action Text」の機能設計を記載する。Action TextはTrixエディタと連携してリッチテキストコンテンツの編集・表示機能を提供する。

### 本機能の処理概要

Action Textは、WYSIWYGエディタによるリッチテキストコンテンツの管理フレームワークである。HTMLとしてコンテンツを保存し、添付ファイル（画像、ファイル等）をActive Storageと連携して埋め込むことができる。

**業務上の目的・背景**：
Webアプリケーションでは、単純なテキストだけでなく、書式付きテキスト（太字、リスト、リンク等）や画像埋め込みが求められるケースが多い。従来、リッチテキストエディタの導入には複雑な設定とデータ管理が必要だったが、Action Textの導入により、Railsアプリケーションで標準的にリッチテキスト機能を提供できるようになった。TrixエディタとActive Storageとの統合により、ファイル添付を含むリッチコンテンツを簡潔に実装できる。

**機能の利用シーン**：
- ブログ記事の作成・編集
- コメント機能でのリッチテキスト入力
- メール本文の作成
- ドキュメント・マニュアルの編集
- 製品説明文の管理

**主要な処理内容**：
1. `has_rich_text`によるモデルへのリッチテキスト属性追加
2. TrixエディタによるWYSIWYG編集
3. HTMLコンテンツの保存と取得
4. 埋め込み添付ファイルの管理（Active Storage連携）
5. プレーンテキストへの変換
6. コンテンツのサニタイズとXSS対策
7. Action Mailableでのリッチテキストメール作成

**関連システム・外部連携**：
- Trixエディタ（JavaScript WYSIWYGエディタ）
- Active Storage（添付ファイル管理）
- Active Record（コンテンツの永続化）
- Nokogiri（HTML解析）

**権限による制御**：
- Action Text自体には権限制御機能はない
- アプリケーション側でコンテンツの編集権限を制御する必要がある

## 関連画面

本機能はエディタコンポーネントとして各種画面に組み込まれる。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | - |

## 機能種別

リッチテキスト編集 / コンテンツ管理 / WYSIWYG

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| body | String | Yes | リッチテキストHTML | - |
| attachments | Array | No | 埋め込み添付ファイル | Active Storage Blob |

### 入力データソース

- Trixエディタからのフォーム送信
- サーバーサイドでのContent生成

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| body | ActionText::Content | リッチテキストコンテンツオブジェクト |
| to_s | String | HTML文字列 |
| to_plain_text | String | プレーンテキスト |
| attachments | Array | 埋め込み添付ファイル一覧 |
| blank? | Boolean | 空判定 |

### 出力先

- データベース（action_text_rich_textsテーブル）
- Active Storage（添付ファイル）

## 処理フロー

### 処理シーケンス

```
1. リッチテキスト属性の定義
   └─ has_rich_text :content
      └─ RichTextモデルとの関連定義
      └─ コンテンツアクセサの定義

2. コンテンツの保存
   └─ model.content = HTML文字列
      └─ ActionText::Content生成
      └─ HTMLの解析・正規化
      └─ 添付ファイルの抽出・保存

3. コンテンツの表示
   └─ model.content.to_s
      └─ 添付ファイルの展開
      └─ HTMLのサニタイズ
      └─ レンダリング
```

### フローチャート

```mermaid
flowchart TD
    A[Trixエディタで編集] --> B[フォーム送信]
    B --> C[ActionText::Content生成]
    C --> D[HTML解析 Nokogiri]
    D --> E{添付ファイル?}
    E -->|Yes| F[action-text-attachment解析]
    F --> G[Active Storage Blob参照]
    G --> H[RichTextレコード保存]
    E -->|No| H
    H --> I[action_text_rich_texts INSERT]
    I --> J[保存完了]
    J --> K{表示時}
    K --> L[to_s呼び出し]
    L --> M[添付ファイル展開]
    M --> N[HTMLサニタイズ]
    N --> O[html_safe出力]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | HTMLサニタイズ | 出力時にXSS対策としてHTMLをサニタイズ | 常時 |
| BR-002 | 添付ファイル形式 | action-text-attachmentタグで添付を表現 | 添付時 |
| BR-003 | プレーンテキスト変換 | HTMLタグを除去してテキスト抽出 | to_plain_text時 |
| BR-004 | ポリモーフィック関連 | RichTextは複数モデルに関連付け可能 | 常時 |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 保存 | action_text_rich_texts | INSERT/UPDATE | リッチテキストコンテンツ保存 |
| 添付 | active_storage_blobs | INSERT | 埋め込み添付ファイル |
| 削除 | action_text_rich_texts | DELETE | コンテンツ削除 |

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

#### action_text_rich_texts

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | name | 属性名（例：content） | |
| INSERT/UPDATE | body | HTML文字列 | |
| INSERT/UPDATE | record_type | モデルクラス名 | ポリモーフィック |
| INSERT/UPDATE | record_id | モデルID | |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | HTML解析エラー | 不正なHTML | Nokogiriが自動修正 |
| - | 添付ファイル未検出 | Blob参照エラー | MissingAttachable表示 |

### リトライ仕様

特になし

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

- RichTextの保存は親モデルのトランザクション内で実行
- 添付ファイルは別途Active Storageのトランザクションで管理

## パフォーマンス要件

- 大量のリッチテキストコンテンツを一覧表示する際はN+1問題に注意
- `with_rich_text_*`スコープでイーガーロード

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

- HTMLサニタイズによるXSS対策
- CSP（Content Security Policy）対応のためのnonce付与
- 添付ファイルのMIMEタイプ検証

## 備考

- Action TextはRails 6.0で導入
- Trixエディタは37signals（Basecamp）が開発
- 暗号化されたリッチテキスト（`has_rich_text :content, encrypted: true`）も対応

---

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

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

### 推奨読解順序

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

RichText、Content、Attachmentの関係を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | rich_text.rb | `actiontext/app/models/action_text/rich_text.rb` | RichTextモデルの構造 |
| 1-2 | content.rb | `actiontext/lib/action_text/content.rb` | Contentクラスの実装 |
| 1-3 | attachment.rb | `actiontext/lib/action_text/attachment.rb` | 添付ファイル表現 |

**読解のコツ**: RichTextはActive Recordモデル、ContentはHTMLを操作するValueObject、Attachmentは埋め込み添付を表現する。

#### Step 2: モデル統合を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | attribute.rb | `actiontext/lib/action_text/attribute.rb` | has_rich_textマクロの実装 |

**主要処理フロー**:
- `has_rich_text`で関連定義とアクセサを追加
- `with_rich_text_*`スコープでイーガーロードを提供

#### Step 3: コンテンツ処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | content.rb | `actiontext/lib/action_text/content.rb` | HTML解析、添付抽出、プレーンテキスト変換 |
| 3-2 | fragment.rb | `actiontext/lib/action_text/fragment.rb` | HTMLフラグメント操作 |

#### Step 4: ビューヘルパーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | tag_helper.rb | `actiontext/app/helpers/action_text/tag_helper.rb` | rich_text_areaヘルパー |
| 4-2 | content_helper.rb | `actiontext/app/helpers/action_text/content_helper.rb` | コンテンツレンダリング |

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

```
has_rich_text :content
    │
    └─ ActionText::Attribute.has_rich_text
           │
           ├─ has_one :rich_text_content, class_name: 'ActionText::RichText'
           │
           └─ define_method :content
                  │
                  └─ rich_text_content&.body

model.content = "HTML文字列"
    │
    └─ ActionText::RichText#body=
           │
           └─ ActionText::Content.new(html)
                  │
                  ├─ ActionText::Fragment.wrap(html)
                  │      │
                  │      └─ Nokogiri::HTML.fragment(html)
                  │
                  └─ attachments抽出
                         │
                         └─ ActionText::Attachment.from_node

model.content.to_s
    │
    └─ ActionText::Content#to_rendered_html_with_layout
           │
           ├─ render_attachments
           │      │
           │      └─ attachment.to_html
           │
           └─ to_html (サニタイズ済みHTML)
```

### データフロー図

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

Trixエディタ ────────▶ フォームデータ ─────────▶ コントローラ
                              │
                              ▼
                     ActionText::Content
                              │
                              ├─▶ Fragment (HTML解析)
                              │
                              └─▶ Attachment抽出
                                       │
                                       ▼
                              Active Storage Blob
                                       │
                                       ▼
                     ActionText::RichText ────────▶ action_text_rich_texts
                              │
                              ▼
ビュー表示 ◀───────── to_rendered_html_with_layout
                              │
                              ├─▶ HTMLサニタイズ
                              │
                              └─▶ 添付ファイル展開
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| action_text.rb | `actiontext/lib/action_text.rb` | ソース | モジュール定義 |
| rich_text.rb | `actiontext/app/models/action_text/rich_text.rb` | モデル | RichTextエンティティ |
| encrypted_rich_text.rb | `actiontext/app/models/action_text/encrypted_rich_text.rb` | モデル | 暗号化RichText |
| attribute.rb | `actiontext/lib/action_text/attribute.rb` | ソース | has_rich_textマクロ |
| content.rb | `actiontext/lib/action_text/content.rb` | ソース | コンテンツ操作 |
| fragment.rb | `actiontext/lib/action_text/fragment.rb` | ソース | HTMLフラグメント |
| attachment.rb | `actiontext/lib/action_text/attachment.rb` | ソース | 添付ファイル表現 |
| attachable.rb | `actiontext/lib/action_text/attachable.rb` | ソース | 添付可能モジュール |
| trix_attachment.rb | `actiontext/lib/action_text/trix_attachment.rb` | ソース | Trix添付変換 |
| plain_text_conversion.rb | `actiontext/lib/action_text/plain_text_conversion.rb` | ソース | プレーンテキスト変換 |
| html_conversion.rb | `actiontext/lib/action_text/html_conversion.rb` | ソース | HTML変換 |
| rendering.rb | `actiontext/lib/action_text/rendering.rb` | ソース | レンダリング |
| serialization.rb | `actiontext/lib/action_text/serialization.rb` | ソース | シリアライゼーション |
| tag_helper.rb | `actiontext/app/helpers/action_text/tag_helper.rb` | ヘルパー | rich_text_area |
| content_helper.rb | `actiontext/app/helpers/action_text/content_helper.rb` | ヘルパー | コンテンツ表示 |
| engine.rb | `actiontext/lib/action_text/engine.rb` | ソース | Rails Engine統合 |
| fixture_set.rb | `actiontext/lib/action_text/fixture_set.rb` | ソース | フィクスチャサポート |
