CarrierwaveがActiveRecordで使えるようになるまで
ActiveRecordにCarrierWaveのUploaderをマウントするには、Uploaderクラスを作成し、それをActiveRecordのModelに記載する
READMEのサンプル
class User < ApplicationRecord
mount_uploader :avatar, AvatarUploader
end
UploderはCarrerWave::Uploader::Baseクラスを継承している
class AvatarUploader < CarrierWave::Uploader::Base
storage :file
end
CarrierWave::Uploader::Baseはlib/carrierwave/uploaders以下のモジュールをincludeしている
Modelの記述に戻る。
定義したUploaderをmountするために使っているmount_uploaderはCarrierWave::Mountモジュールに定義してある。
CarrierWave::MountはCarrierWave本体でrequireされている。
※ CarrierWave自体はrails起動時にrequireされる
lib/carrierwave.rbを読み込み時にActiveRecordがあれば lib/carrierwave/orm/activerecord.rbをrequireされていて、このCarrierWave::ActiveRecordモジュールがCarrierWave::Mountをincludeしている
CarrierWave::ActiveRecordモジュールはActiveRecord::Baseに対してextendされているので、ここで定義されているprivateメソッドのmount_baseはどのActiveRecordのクラスでも利用できるようになる
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を実行する。
superで実行されたCarrierWave::Mount#mount_base内で、Uploaderの初期化とCarrierWave用の拡張メソッドを動的に定義する。
この中にstore_#{column}!メソッドもある
CarrierWave::Mount#mount_baseから抜けたら、CarrierWave::ActiveRecord#mount_baseの続きを実行するが、そこでafter_save: sotre_#{column}! のコールバックが定義される
つまり、ActiveRecordのafter_saveのタイミングで、store_#{column}!でUploaderのstore!メソッドが実行されるようになる。
Uploderのstore!はバックエンドのサービスに依存する。
carrierwave-awsではこのような実装。