現象について
画像アップローダのCarrierWaveを使っていて、アップロードされた画像のjpgのサムネイルを作る時、ファイルの拡張子を変えてファイル名を設定しようと以下の様なコードを用意していた。
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick
version :thumb do
process :convert => "jpg"
def full_filename(for_file)
return unless for_file.present?
filename = super(for_file)
filename.chomp(File.extname(filename)) + '.jpg'
end
end
(他は略)
end
class User < ApplicationRecord
mount_uploader :image, ImageUploader
end
このUserのimageに image.pngを登録した後、拡張子以外は同じimage.jpgを登録して更新すると、thumb_image.jpgが消えてしまう現象が起きた。
(※ image.pngを登録している段階では、thumb_image.jpgは存在する)
原因
CarrierWaveでは、ファイルを登録後、versionsを作成して古いversionsを削除しているが、この時、古いversionsとファイル名が一緒なため
ファイルを削除する際、新しく作ったversionの画像も削除してしまっている。
元のファイル名が一致した時は削除しないように回避されているが、別のファイル名だがversionsで一致すると言うケースでは回避策が取られていない。(元のソースコードだと発生しないので当然だけど)
対策1: 以前のバージョンのファイルを削除しないようにする
CarrierWaveで画像更新時に以前のバージョンを削除しないを参考に、以前のバージョンを削除しないようにすれば解決はする。
古いファイルが残ってしまうので、使えないケースもありそう
対策2: 生成タイミングを削除タイミングの後にする
バッドノウハウ感のある対策だけど、以下の様に、mount_uploaderでafter_save に作成と削除のコールバックが登録されているので、作成のコールバックを登録し直すことで、削除後に作成する様になる
class User < ApplicationRecord
mount_uploader :image, ImageUploader
skip_callback :save, :after, :store_image!
save_after :store_image!
end
注意: :store_iamge!の imageの部分はカラム名なので、適宜書き換えてください
取り敢えず
対策2を採用したんだけど、もっと良い方法があれば是非指摘ください