`has_many_attached`に複数添付ファイルの合計バイトサイズを取得するメソッドを追加

rails/rails

has_many_attachedで管理する複数の添付ファイルについて、byte_sizeメソッドで合計バイトサイズを一度に取得できるようになりました。これにより、ストレージ使用量の検証やUIでの容量表示が簡潔に記述できます。

背景

Active Storageのhas_many_attachedは複数ファイルの添付を管理しますが、これまで添付ファイル群の合計サイズを取得するAPIが存在しませんでした。合計バイトサイズを得るには、blobs.pluck(:byte_size).sumblobs.sum(&:byte_size)を呼び出す必要があり、利用側のコードに実装の詳細が露出していました。has_one_attachedに対応するAPIが存在する中で、has_many_attached側にのみこのヘルパーが欠けている状態が課題でした。

技術的な変更

ActiveStorage::Attached::Many クラスにbyte_sizeメソッドが追加されました。実装はblobs.pluck(:byte_size).sumの1行に集約されています。

変更後:

# Returns the combined size in bytes of all attached blobs.
#
#   document.images.byte_size # => 2048
def byte_size
  blobs.pluck(:byte_size).sum
end

blobs.pluck(:byte_size)はSQLのSELECT byte_size FROM active_storage_blobs WHERE ...に相当するクエリを発行し、Rubyオブジェクトとしてblobを全件ロードせずにバイトサイズの配列だけを取得します。その後.sumでRuby側で合算するため、メモリ効率に配慮した実装になっています。

テストでは、DBに永続化済みの添付と未永続の添付(=で代入した直後)の両方のケースが追加されており、どちらのシナリオでも正しく合計サイズを返すことが確認されています。

test "getting the combined byte size of persisted attachments" do
  blobs = [ create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg") ]
  @user.highlights.attach(blobs)

  assert_equal blobs.sum(&:byte_size), @user.highlights.byte_size
end

test "getting the combined byte size of non persisted attachments" do
  blobs = [ create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg") ]
  @user.highlights = blobs

  assert_equal blobs.sum(&:byte_size), @user.highlights.byte_size
end

設計判断

pluckを用いたクエリ集約が採用されました。blobs.map(&:byte_size).sumのようにblobオブジェクトを全件ロードする実装ではなく、pluckでバイトサイズの値だけを取得することで、blobのレコード数が増えても不要なカラムのロードを避けられます。

また、メソッドの追加先をActiveStorage::Attached::Manyに限定しており、has_one_attachedに対応するActiveStorage::Attached::Oneには変更がありません。has_one_attachedの場合はblobが1つでありblob.byte_sizeで直接アクセスできるため、Many側のみに集約ヘルパーを設ける設計は自然な判断といえます。

まとめ

本PRは1メソッドの追加という小さな変更ながら、has_many_attachedのAPIに欠けていたストレージ計測の起点を提供します。blobs.pluckを用いた実装により、添付ファイル数が増加してもメモリ効率を保ちながら合計サイズを取得でき、ファイルサイズバリデーションや容量表示といったユースケースで利用側のコードをシンプルに保てます。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
0f5e9a1a

この記事は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リンク記法の正確性

ファイル名付きのシンタックスハイライトやPR番号のリンク記法がガイドライン通りに正しく使用されています。

対象読者への適合性 ✓ PASS

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

Active Storageやpluckなどの専門用語を前提としており、専門知識を持つエンジニアという対象読者に適切に設定されています。

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

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

各セクションが総論→各論で構成され、各パラグラフはトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が守られており、可読性が高いです。

Diff内容との照合 ✓ PASS

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

記事内で引用されているコードブロック(メソッド実装、テストコード)は、提供されたDiffの内容と完全に一致しており、正確です。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

`has_many_attached`や`pluck`などの技術用語が、文脈に沿って正確に使用されています。

説明の技術的正確性 ✓ PASS

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

`pluck`の挙動やメモリ効率に関する説明は技術的に正確であり、変更の意y図を正しく伝えています。

事実の突合 ✓ PASS

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

記事内の主張はすべてPRのDiffやDescription、またはコードから読み取れる技術的事実に基づいており、ハルシネーションは検出されませんでした。

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

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

PR番号(#45201)が正確に記載されています。

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

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

記事のタイトルは、元のPRの主題「Adds ability to get the combined bytes_size of all attached blobs」を的確に表現しています。

外部知識の正確性 ✓ PASS

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

バージョン情報やリリース予定など、PR情報に基づかない外部知識の記述は見られませんでした。

時間表現の正確性 ✓ PASS

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

「これまで...存在しませんでした」「...できるようになりました」といった時間表現は、PRの文脈と一致しており正確です。