Closed4

CarrierwaveがActiveRecordで使えるようになるまで

tkt182tkt182

ActiveRecordにCarrierWaveのUploaderをマウントするには、Uploaderクラスを作成し、それをActiveRecordのModelに記載する

https://github.com/carrierwaveuploader/carrierwave/tree/master?tab=readme-ov-file#activerecord

READMEのサンプル

class User < ApplicationRecord
  mount_uploader :avatar, AvatarUploader
end

UploderはCarrerWave::Uploader::Baseクラスを継承している

class AvatarUploader < CarrierWave::Uploader::Base
  storage :file
end

https://github.com/carrierwaveuploader/carrierwave/blob/550e423fbd5cd45cac262e2c5d13bfe778be5093/lib/carrierwave/uploader.rb

CarrierWave::Uploader::Baselib/carrierwave/uploaders以下のモジュールをincludeしている

tkt182tkt182

Modelの記述に戻る。

定義したUploaderをmountするために使っているmount_uploaderCarrierWave::Mountモジュールに定義してある。

https://github.com/carrierwaveuploader/carrierwave/blob/550e423fbd5cd45cac262e2c5d13bfe778be5093/lib/carrierwave/mount.rb#L134

CarrierWave::MountはCarrierWave本体でrequireされている。
※ CarrierWave自体はrails起動時にrequireされる

https://github.com/carrierwaveuploader/carrierwave/blob/550e423fbd5cd45cac262e2c5d13bfe778be5093/lib/carrierwave.rb#L102

lib/carrierwave.rbを読み込み時にActiveRecordがあれば lib/carrierwave/orm/activerecord.rbをrequireされていて、このCarrierWave::ActiveRecordモジュールがCarrierWave::Mountをincludeしている

https://github.com/carrierwaveuploader/carrierwave/blob/550e423fbd5cd45cac262e2c5d13bfe778be5093/lib/carrierwave.rb#L66-L70

https://github.com/carrierwaveuploader/carrierwave/blob/550e423fbd5cd45cac262e2c5d13bfe778be5093/lib/carrierwave/orm/activerecord.rb#L7

CarrierWave::ActiveRecordモジュールはActiveRecord::Baseに対してextendされているので、ここで定義されているprivateメソッドのmount_baseはどのActiveRecordのクラスでも利用できるようになる

https://github.com/carrierwaveuploader/carrierwave/blob/550e423fbd5cd45cac262e2c5d13bfe778be5093/lib/carrierwave/orm/activerecord.rb#L68

tkt182tkt182

CarrierWaveがmount_uploaderを設定したカラムが更新されたら対象のファイルがアップロードされるところの処理がどう定義されているのかを調べるのが目的だった。

ここまでmount_uploaderが使えるようになるまで(CarrierWave::Mountがincludeされるまで)のコードを追ってみた。
ここからは、レコードが保存されたらファイルがアップロードされ始めるまでのコードを追ってみる。

ActiveRecord::BaseにはCarrierWave::ActiveRecordがextendされているため、mount_uploaderを実行するレシーバはActiveRecord::CarrierWaveとなる。
なので、mount_uploader内で一番最初に実行されるmount_baseは、まずCarrierWave::ActiveRecord#mount_baseが実行され、その内部のsuperでCarrierWave::Mount#mount_baseを実行する。

https://github.com/carrierwaveuploader/carrierwave/blob/550e423fbd5cd45cac262e2c5d13bfe778be5093/lib/carrierwave/orm/activerecord.rb#L12
https://github.com/carrierwaveuploader/carrierwave/blob/550e423fbd5cd45cac262e2c5d13bfe778be5093/lib/carrierwave/mount.rb#L327

superで実行されたCarrierWave::Mount#mount_base内で、Uploaderの初期化とCarrierWave用の拡張メソッドを動的に定義する。
この中にstore_#{column}!メソッドもある

https://github.com/carrierwaveuploader/carrierwave/blob/550e423fbd5cd45cac262e2c5d13bfe778be5093/lib/carrierwave/mount.rb#L367-L369

CarrierWave::Mount#mount_baseから抜けたら、CarrierWave::ActiveRecord#mount_baseの続きを実行するが、そこでafter_save: sotre_#{column}! のコールバックが定義される

https://github.com/carrierwaveuploader/carrierwave/blob/550e423fbd5cd45cac262e2c5d13bfe778be5093/lib/carrierwave/orm/activerecord.rb#L25

つまり、ActiveRecordのafter_saveのタイミングで、store_#{column}!でUploaderのstore!メソッドが実行されるようになる。

このスクラップは2025/01/31にクローズされました