Action Text のダイレクトアップロードイベントに `id`・`file` プロパティと2つの新イベントを追加

rails/rails

Action Text の AttachmentUpload クラスが発火するダイレクトアップロードイベントに idfile プロパティが追加され、Active Storage のイベント仕様との整合性が取られました。あわせて direct-upload:initializedirect-upload:before-blob-requestdirect-upload:before-storage-request の3イベントが新たに追加され、ファイル添付ライフサイクル全体を JavaScript から観測できるようになります。

背景

Action Text のファイル添付処理は #52680direct-upload:start / direct-upload:progress / direct-upload:end の各イベントが追加されましたが、Active Storage の DirectUploadController と比べると実装に2つの乖離がありました。第一に、event.detail オブジェクトに idfile プロパティが含まれておらず、Active Storage のドキュメントで示されているイベント仕様を満たしていませんでした。第二に、アップロードのライフサイクルのうち「Blob メタデータ取得リクエスト前」と「ストレージへのアップロードリクエスト前」の2フェーズに対応するイベントが欠落していました。

また、ドキュメント上の誤りも存在していました。イベントのターゲット要素が <input> と記載されていましたが、実際には AttachmentUpload クラスが <trix-editor> 要素をターゲットとしてイベントを発火していました。本PRはコード・ドキュメント・テストの3つを同時に修正することでこの不整合を解消しています。

技術的な変更

dispatch() メソッドへの2プロパティ追加と、2つのコールバックメソッドの実装が変更の核心です。

dispatch() メソッドの変更:

// 変更前
dispatch(name, detail = {}) {
  detail.attachment = this.attachment
  return dispatchEvent(this.element, `direct-upload:${name}`, { detail })
}

// 変更後
dispatch(name, detail = {}) {
  detail.attachment = this.attachment
  detail.file = this.directUpload.file
  detail.id = this.directUpload.id
  return dispatchEvent(this.element, `direct-upload:${name}`, { detail })
}

すべてのイベントに file(アップロード対象の File オブジェクト)と idDirectUpload インスタンスに割り当てられた識別子)が自動的に付与されます。

新規イベントのためのコールバック実装:

AttachmentUpload クラスは DirectUpload のデリゲートとして機能しており、以下の2つのコールバックメソッドが追加されました。

directUploadWillCreateBlobWithXHR(xhr) {
  this.dispatch("before-blob-request", { xhr })
}

directUploadWillStoreFileWithXHR(xhr) {
  this.dispatch("before-storage-request", { xhr })
  // 既存の progress イベントハンドラが続く
}

これらのメソッド名は Active Storage の DirectUploadController が実装するコールバックと同名であり、DirectUpload ライブラリが定めるデリゲートインターフェースに準拠しています。さらに、コンストラクタで dispatch("initialize") が呼ばれるようになり、インスタンス生成直後のイベントも観測できます。

この変更により、Action Text が発火するイベントの全体像は以下の通りになりました。

イベント名 event.detail タイミング
direct-upload:initialize {id, file, attachment} インスタンス生成直後
direct-upload:start {id, file, attachment} アップロード開始時
direct-upload:before-blob-request {id, file, xhr, attachment} Blob メタデータ取得リクエスト前
direct-upload:before-storage-request {id, file, xhr, attachment} ストレージへのアップロードリクエスト前
direct-upload:progress {id, file, progress, attachment} アップロード進行中
direct-upload:error {id, file, error, attachment} エラー発生時
direct-upload:end {id, file, attachment} アップロード完了時

ドキュメントのイベントターゲットも <input> から <trix-editor> に修正されています。

テストについては、システムテスト actiontext/test/system/rich_text_editor_test.rb に2件のケースが追加されました。成功パスではイベントが initialize → start → before-blob-request → before-storage-request → progress → end の順に発火することを検証し、失敗パスではネットワークオフライン時に error イベントが発火することを確認しています。各イベントの detailid: "Number"file: "File"attachment: "ManagedAttachment" が含まれるかを型レベルで検証する assert_direct_upload_event ヘルパーも実装されています。

設計判断

Active Storage の DirectUploadController の実装スタイルを模倣する方針が採用されました。directUploadWillCreateBlobWithXHRdirectUploadWillStoreFileWithXHR というメソッド名はそのままデリゲートプロトコルのコールバック名であり、DirectUpload ライブラリが対応するタイミングで自動的に呼び出します。イベント名やプロパティ名の設計を Active Storage 側と一致させることで、開発者が両方のアップロード機構を扱う際に学習コストを最小化できます。

idfiledispatch() メソッド内で一括付与する方式も注目に値します。各イベント発火箇所でプロパティを個別に渡すのではなく、DirectUpload インスタンスから取得して常に付与することで、将来イベントを追加した場合にもプロパティの付け忘れが起きない構造になっています。

まとめ

この変更は、Action Text のダイレクトアップロードイベントを Active Storage の仕様と完全に整合させたものです。idfile の追加とイベント種別の拡充により、アップロードライフサイクルの各フェーズで XHR を差し替えたり進捗を細かく追跡したりする実装が、ドキュメント通りのインターフェースで実現できるようになりました。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
be293f74

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文(総論)→背景・技術的な変更・設計判断(各論)→まとめ(結論)の3部構成が明確に適用されており、ガイドラインに完全に準拠しています。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライト(```javascript:ファイルパス)およびGitHubのPRリンク記法([#123](URL))が正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

Action TextやActive Storageの内部実装に関する内容であり、専門知識を持つエンジニアという対象読者に完全に適合しています。冗長な説明もありません。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論→各論で構成され、各段落がトピックセンテンスで始まっています。1段落1トピックの原則が守られており、段落長も適切です。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事内のコードブロックは、提供されたDiff情報と完全に一致しています。ファイル名も正確です。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「AttachmentUpload」「DirectUpload」「デリゲート」「trix-editor」などの技術用語が、PRの文脈に沿って正確に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

イベントプロパティの追加、新規コールバックの実装、テストの検証内容など、すべての技術的な説明がDiff内容と整合しており、正確です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内のすべての主張(Active Storageとの乖離、ドキュメントの誤り、テストの追加内容など)は、PRのDescriptionやDiff内容によって裏付けられており、ハルシネーションは検出されませんでした。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#53812、#52680)やその他の固有名詞(クラス名、メソッド名)はすべて正確です。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事のタイトルはPRの主題(id/fileプロパティと新イベントの追加)を正確かつ簡潔に表現しており、PR Titleよりも包括的で優れています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

記事に含まれる情報はすべてPRで提供された範囲内に留まっており、バージョンサポート情報などのPRに基づかない外部知識の追記はありません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

「乖離がありました」「欠落していました」といった過去形の表現が、PRで言及されている変更前の状態を正しく反映しており、時間表現は正確です。