Techioz Blog

Rails はイメージを再生成せずに Active Storage を Image Magick から Libvips に移行します

概要

Rails 7 システムには約 50,000 枚の写真が Active Storage に保存されており、バリアントを使用してさまざまなサイズに変換しています。現在、image_processing のバックエンドとして Image Magick を使用していますが、最近の Rails バージョンのデフォルトでもある libvips に変更したいと考えています (たとえば、これを参照)

残念ながら、バリアントに渡されるオプション ハッシュは、アプリケーションの libvips 用に変更する必要があります。例: (さらに多くの例がここにあります)

variant(format: :jpg, strip: true, quality: 80) # imagemagick
variant(format: :jpg, saver: { strip: true, quality: 80 }) # libvips / image_processing

Rails はこのハッシュを内部で使用してバリアントを一意に識別します。したがって、libvips に適合するようにバリアントの説明を変更すると、Rails はそれ以上ではないにしても 100,000 枚のイメージを再生成することになりますが、これは明らかに避けたいことです。

この問題に対する標準的な解決策はありますか?

私が検討していたオプションの 1 つは、最初に imagemagick バリアントが既に存在するかどうかをテストし、存在する場合はそれを使用することです。

def create_variant
  magick_variant = image.variant(format: :jpg, strip: true, quality: 80)
  return magick_variant.processed.url if magick_variant.processed?
  
  image.variant(format: :jpg, saver: { strip: true, quality: 80 }).processed.url
end

残念ながら、VariantWithRecord#processed? Rails 7.1 ではプライベートになったため、持続可能なソリューションではありません。

解決策

使用するバリアント変換の大部分 (約 80%) を収集し、移行前と移行後にダイジェストを計算し、active_storage_variant_records に保存されているダイジェストを手動で更新することで移行を実行しました。

例えば:

UPDATE `active_storage_variant_records` 
SET `variation_digest` = CASE `variation_digest`
   WHEN '8HYTSoAKrOz5PQZaB5rF21hDWks=' THEN 'ols+mvCHaSFFmjPwGcc9zwr6A6Y='
   WHEN 'LzJ443LpJ9ZNnqCVgpoG3j43nC0=' THEN 'Safska55MupNqvs4kO2JOJxLNoU='
END
WHERE `active_storage_variant_records`.`variation_digest` 
IN ('8HYTSoAKrOz5PQZaB5rF21hDWks=', 'LzJ443LpJ9ZNnqCVgpoG3j43nC0=');

これが機能するのは、VariantRecord が has_one_attached を再度使用し、バリアント BLOB が格納されるキーがダイジェストから独立しているためです。