Action Text のダイレクトアップロードイベントに `id`・`file` プロパティと2つの新イベントを追加
Action Text の AttachmentUpload クラスが発火するダイレクトアップロードイベントに id と file プロパティが追加され、Active Storage のイベント仕様との整合性が取られました。あわせて direct-upload:initialize・direct-upload:before-blob-request・direct-upload:before-storage-request の3イベントが新たに追加され、ファイル添付ライフサイクル全体を JavaScript から観測できるようになります。
背景
Action Text のファイル添付処理は #52680 で direct-upload:start / direct-upload:progress / direct-upload:end の各イベントが追加されましたが、Active Storage の DirectUploadController と比べると実装に2つの乖離がありました。第一に、event.detail オブジェクトに id と file プロパティが含まれておらず、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 オブジェクト)と id(DirectUpload インスタンスに割り当てられた識別子)が自動的に付与されます。
新規イベントのためのコールバック実装:
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 イベントが発火することを確認しています。各イベントの detail に id: "Number"・file: "File"・attachment: "ManagedAttachment" が含まれるかを型レベルで検証する assert_direct_upload_event ヘルパーも実装されています。
設計判断
Active Storage の DirectUploadController の実装スタイルを模倣する方針が採用されました。directUploadWillCreateBlobWithXHR と directUploadWillStoreFileWithXHR というメソッド名はそのままデリゲートプロトコルのコールバック名であり、DirectUpload ライブラリが対応するタイミングで自動的に呼び出します。イベント名やプロパティ名の設計を Active Storage 側と一致させることで、開発者が両方のアップロード機構を扱う際に学習コストを最小化できます。
id と file を dispatch() メソッド内で一括付与する方式も注目に値します。各イベント発火箇所でプロパティを個別に渡すのではなく、DirectUpload インスタンスから取得して常に付与することで、将来イベントを追加した場合にもプロパティの付け忘れが起きない構造になっています。
まとめ
この変更は、Action Text のダイレクトアップロードイベントを Active Storage の仕様と完全に整合させたものです。id・file の追加とイベント種別の拡充により、アップロードライフサイクルの各フェーズで XHR を差し替えたり進捗を細かく追跡したりする実装が、ドキュメント通りのインターフェースで実現できるようになりました。