やりたいこと
gem の carrierwave
で新しいリサイズのバージョンを作る。
新しく retina
というバージョンを作る場合、コードだけで言えば、アップローダーの中で
class ImageUploader < CarrierWave::Uploader::Base
version :retina do
process :resize_to_fit => [640, 640]
end
end
と書いて、新しく画像を保存すれば 640 x 640 でリサイズしたものも勝手に保存してくれる。
ただ新しく保存した画像は自動的に 640 x 640 のものが作られるが、
既存の画像は作られず、 @user.image.retina
などと書くとエラーが起こる。
@user.image.retina.presence || @user.image
とかにすればもちろん動くが、 retina
と使いたい場所全てに書かないとなので、
バージョンが増えてきたら崩壊する。
そこで今回、既存の画像ファイルの retina
でリサイズした画像を作っていく。
モデル
User |
---|
id |
image |
user モデルがあり、user はカラムに image を持っている。 |
class User < ActiveRecord::Base
mount_uploader :image, ImageUploader
end
image
にカラムに ImageUploader の設定を反映させる。
class ImageUploader < CarrierWave::Uploader::Base
version :retina do
process :resize_to_fit => [640, 640]
end
end
こちらの設定は retina
のバージョン以外は省略。
リサイズ
リサイズは recreate_versions!
というメソッドを使うとできる。
例えば
User.find(1).image.recreate_versions!
で id が 1 のユーザーの画像の retina
バージョンが作られる。
もちろん全ユーザーの既存の画像を作り直したいので
User.find_each do { |user| user.image.recreate_versions! if user.image.present? }
とかにするとユーザーの画像が存在した場合にだけ画像を作り直す。
また画像は恐らく量が多いので find_each
を使っている。
これをコンソールなどで叩いたらいいのだが、
- コンソールで打つの面倒臭い
- 本番環境でコンソールあんまり打ちたくない
等々あるので、
どこか適当なファイルに先程のコードを書き(今回はlib/tasks/recreate_image.rb
)
rails runner lib/tasks/recreate_image.rb
と叩けば画像のリサイズ完成。
は一応するのだが、
エラーが起きた場合などにしっかり終えるようにしたいのと、
どのくらいまでリサイズが進んでるかとかも見たいので例外処理も加えて
User.find_each do |user|
begin
p user.id
usere.image.recreate_versions! if user.image.present?
rescue
p "#{user.id} recreate failed."
end
end
とかすると、多少雑ではあるけど、
id を見て進捗がわかるのと、もしリサイズがうまくいかなかった時はその画像の id を表示してくれるようにしてる。
リサイズできなかったやつは slack などで通知させようとも思ったが、
既存画像のリサイズ自体そんなに頻繁にやるものでもないので今回はやらなかった。
また、そもそも rails runner
や コンソール
を使わなくても、
どこかのアクションにこの処理を書けばいいのだが、URL を知ってさえすれば誰でも処理を回せてしまうのでコマンド対応にした。