やりたかったこと
- 画像アップロード時に時系列で過去分履歴を残したいのでfilenameに日時をいれたい
- 特定解像度にresizeしたものも用意したい
サンプルコード
- filenameをoverrideしてoriginal_filenameに日時を追加する
- インスタンス変数化してstore時とupload時のfilenameを一致させる
- smallとlargeというversionでresizeする
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
def filename
@name ||= "#{Time.zone.now.strftime("%Y-%m-%d-%H-%M-%S")}-#{super}" if super
end
version :small do
process resize_to_fill: [100, 100]
end
version :large do
process resize_to_fill: [800, 600]
end
end
発生した問題
- storeしたfilenameとuploadされたfilenameが1秒ずれる
- resizeしたfileにおいてだけ稀に発生する
原因
def filename
@name ||= "#{Time.zone.now.strftime("%Y-%m-%d-%H-%M-%S")}-#{super}" if super
end
ここでnameをインスタンス変数化することで、resize時にもfilenameが同一になるだろうと考えていた。
しかし実際resize時の処理はCarrierwave内部でcallbackとして呼びだされ、同クラスの別インスタンスを生成して行われる。
その結果resize時には別インスタンスでこのfilenameが呼ばれるため、nameはnilとなり処理時刻で生成されるためだった。
解決方法
rezise時のfilenameとして、原寸画像Upload時のインスタンスのものを使うように指定した。
コード変更点
version :small do
process resize_to_fill: [100, 100]
+
+ def filename
+ model.send(mounted_as).filename
+ end
end
version :large do
process resize_to_fill: [800, 600]
+
+ def filename
+ model.send(mounted_as).filename
+ end
end
model.send(mounted_as)は、マウントしてるmodelのattributeです。
Versionの処理内でこれを呼び出すことで原寸画像Upload時のインスタンスを取得しています。
これ解決一応したけどversion毎に毎回これ指定するの面倒なので、もっといい解決方法あるんじゃないのか?とも思うので、もっといい方法あったら追記します。