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してあげると良さそうです。