ActiveStorageを使うにあたって、アップロードできたかどうかを調べるために、アップロードをどの処理で実施しているか調べたので、覚書として。(アップロードできたかどうかについては、これから改めて調査)
アプリケーションコードに近い方から遠い方へ順に追っていきます。
前提条件
- activestorage のバージョンは5.2.2を使用する
- 属性の定義に
has_one_attached
を使用する - attachするファイルはHTMLからアップロードしたファイルを使用する
- ファイル保存サービスはローカル(S3やGCSではない)を使用する
ActiveStorage::Attached::Macros
ActiveRecord::Baseを継承するモデルクラス内に定義したhas_one_attached
の属性に対して、値が代入された時にattach
メソッドを実行します。
ActiveStorage::Attached::One
ActiveStorage::Attached::One.attach
メソッドが create_blob_from
を実行します。
ActiveStorage::Attached
ActiveStorage::Attached. create_blob_from
メソッドで、attachableのクラスによって処理を分けています。
今回はアップロードされたファイルを属性に指定したので、
ActiveStorage::Blob.create_after_upload!
を実行します。
ActiveStorage::Blob
ActiveStorage::Blob.create_after_upload!
がActiveStorage::Blob.build_after_upload
を実行します。
ActiveStorage::Blob.build_after_upload
が ActiveStorage::Blob
をnew
して、upload
を実行します。
ActiveStorage::Blob#upload
が service
インスタンスのupload
を実行します。
このservice
は、公式ガイドのセットアップで service
に指定した Disk
やS3
が ActiveStorage::Service::DiskServiceやActiveStorage::Service::S3Serviceをnewしたインスタンスが格納されています。
今回はローカルディスクを保存サービスに指定しているので、ActiveStorage::Service::DiskService
のupload
を実行します。
ActiveStorage::Service::DiskService
ActiveStorage::Service::DiskService.upload
で IO.copy_stream でファイルを Rails.root/storage/
にコピーして、アップロード処理が終わります。
instrument
のブロックで囲まれていますが、これは ActiveSupport::Notifications.instrument
をラップするためのメソッドです。
ログを見ると、
Disk Storage (31.0ms) Uploaded file to key: fH4PhWtse6qwM6hBqsoqqmtz (checksum: ci+Mp/YmvV385qYcTJnlgg==)
こんな感じのログが、アップロードファイルを属性に代入、またはattachの処理あたりで流れてくると思います。
感想
調べ終わってから記事を書いたので思考とは逆順になっています。
調べ始める前は、モデルクラスをsave
するタイミングでupload
的なメソッドをアプリケーションコードに近いところで実行していると予想していたので、attach
がそれに相当すると気づくまで時間がかかりました。
save
に合わせてファイルを保存するようにしたい場合は、直接属性に代入するのではなく、after_save
かそれに近いタイミングでattach
してあげると良さそうです。