PaperclipでAWS上にデータを保管していましたが、Rails5.2から追加されたActiveStorageの利用を推奨として、Paperclipがdeprecatedになったため、ActiveStorageへの移行を行うことにしました。
Paperclip内の移行手順のドキュメントに従うことで基本的にはスムーズに移行できますが、英語が完璧でなかったり細かいイレギュラーな部分でつまずいたので、備忘録として残しておきます。
- PaperclipのActiveStorageへの移行ドキュメント https://github.com/thoughtbot/paperclip/blob/master/MIGRATING.md
- 上記の日本語翻訳版 https://techracho.bpsinc.jp/hachi8833/2018_05_21/56668 ※一部原文が追加更新されていてこちらにない部分があります
作業順
- ActiveStorageのインストールとストレージの設定
- mini_magickのgem追加
- paperclipのgemを外す
- モデルにActiveStorageの設定をする
- 元データをActiveStorageのレコードに再登録する ★
- Viewの更新
- default_url対応 ★
重点はこの★のところだけです。あとは、ドキュメントどおりなので割愛。
ActiveStorageにデータを移行する
上記作業順の1,2,3まで終わったら、モデルにActiveStorageの設定をします。
has_one_attached :photo
元データからActiveStorageのレコードに再登録する
rakeタスクで、元データを一つずつ順番にActiveStorageデータとして再登録します。
この作業の良い点
- development環境からできる。
- 元データを一旦残した状態にしておける。(最悪問題があった場合に救出できる)
一つのデータあたりにかかる時間は画像サイズにもよりますが、平均1,2秒程度でした。移行したいもののデータ量によっては、実行するタイミングを考えた方が良さそうです。
paperclipの移行ドキュメントに掲載されているrakeタスクからの変更点は以下のとおりです。
- ファイル名に日本語URLが含まれている場合の対応
- ファイルがなぜかなくなっていてエラーが出たので、ファイルが開けない場合の対応
※また私の場合、photoの親モデルであるUserモデルのコールバックが悪さをしてつまずきました。このタスクは一回しか走らせないので、いらないコールバックはコメントアウトしておくと安全かも。
namespace :users do
desc 'Migrate paperclip to ActiveStorage'
task migrate_to_active_storage: :environment do
User.where.not(photo_file_name: nil).find_each do |user|
# 移行前のオリジナルファイル名を参照
image = user.photo_file_name
# 以下の一行はpaperclipの移行ドキュメントにはありましたが、URLパターンによっては不要
# ext = File.extname(image)
# 移行前のURLパターン
image_original = CGI.unescape("#{user.id}_#{image}")
# 移行前URLのフルパス
# URI.encodeで日本語や記号を含むファイル名に対応
photo_url = URI.encode "https://s3.amazonaws.com/hogehoge/photos/original/#{image_original}"
# open()で何らかの理由でファイルが開けなかった場合にエラーを返す
begin
uri = open(photo_url)
rescue => e
p "ERROR: #{e}"
end
p "URL #{photo_url} e? #{e.blank?}"
# ファイルが正しく開けたら、ActiveStorageで保存
user.photo.attach(io: open(uri),
filename: user.photo_file_name,
content_type: user.photo_content_type) if e.blank?
end
end
end
上記のrakeタスクを実行。
$ rake users:migrate_to_active_storage
mini_magickの追加
ドキュメント内にそっと書かれていた、mini_magick
を追加してねという一文をスルーしてしまったために、この流れの最後までやって試したときに、以下のようなエラーが出ました。
LoadError (cannot load such file -- mini_magick)
どのタイミングでも良いので、mini_magickを入れましょう。
gem 'mini_magick'
paperclipのdefault_url・・・
paperclipのdefault_url設定の良い移行の仕方を探していたのですが、ActiveStorageではその機能はない模様。
decoratorやhelperメソッドでカバーするしかなさそうです。
私の場合は、Userのアバターがない場合の表示をするのに、decoratorで対応しました。(gem active_decorator)
module User
def avatar(size='mini')
px =
case size
when 'mini' then MINI
when 'thumb' then THUMB
when 'small' then SMALL
else MINI
end
# MINI,THUMB,SMALLの定数はconfig/initializers/constants.rbにまとめて持っている
if self.photo.present?
image_tag(self.photo.variant(resize: "#{px}x#{px}"), class: 'avatar')
else
# webpackerで画像を管理。cssで画像サイズを調整。
image_pack_tag("noimage.png", class: "avatar #{size}")
end
end
end