エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

外部で生成したデータをActive Storageでattachしたいとき

つまりこうゆうことです。

探した範囲でははっきりとした情報が見つからなかったので、めも。

このようなモデルがあるばあい、

class Article < ApplicationRecord
  has_one_attached :image
end

たとえばこのようにすることで storage にデータを格納できますが、Rails は元のデータとは別のオブジェクトを storage に生成します。

Article.find(id).image(filename: image_filename, io: File.read(image_filename))

worker が生成したデータの出力先を制御できるであれば、worker から storage へ直接出力させて Rails では attach 情報だけを更新することで実現できます。

blob =
  ActiveStorage::Blob.create(
    key: 'key-of-object',                # 格納したファイルのキー(実際に格納されているファイルのファイル名や S3 のキー)
    filename: 'something.jpg',           # ダウンロードする時のファイル名
    content_type: 'image/jpeg',          # content-type
    byte_size: 12345,                    # 格納したファイルのバイトサイズ
    checksum: 'TcZwnbeihC6rAB8p5LeRuQ==' # 格納したファイルのチェックサム
  )

Article.find(id).image.attach(blob)

チェックサムOpenSSL::Digest::MD5 で生成して Base64エンコードしたものです。

Base64.strict_encode64(OpenSSL::Digest::MD5.digest(格納したファイルの内容))

ローカルに格納されているばあい、キー(ファイル名)の先頭 4 文字を 2 文字ずつ使ったサブディレクトリに格納されます。

たとえば格納先のディレクトリが storage/ で格納するファイルのファイル名が ABCDEFGHIJKLMNOPQRSTUVWX だったばあい、次のように storage/AB/CD/ABCDEFGHIJKLMNOPQRSTUVWX というパスになります。

storage/
└ AB/
   └ CD/
      └ ABCDEFGHIJKLMNOPQRSTUVWX