画像を表示しているページでActiveStorage::InvariableError
に遭遇したためまとめておきます。
ActiveStorage::InvariableErrorとは?
Railsのドキュメントには以下のように記載されていました。
「可変」という部分が微妙にわかりづらいため、記載されているそれぞれのメソッドを確認して行きます。
ActiveStorage::Blob#variant が可変でない blob に対して呼び出されたときに発生。ActiveStorage::Blob#variable?を使って、blobが可変かどうかを判断する。
ActiveStorage::Blob#variant
variant
メソッドは画像のサイズや色を変更することができるメソッド。
以下の例では画像の高さと幅を100pxにリサイズしています。
(サイズだけでなく色も変更できるため「可変」と書かれていたんですね👀)
avatar.variant(resize_to_limit: [100, 100]).processed.url
ActiveStorage::Blob#variable?
variant
メソッドによって変換可能な画像形式の場合にtrue
を返します。
変換可能な画像形式はActiveStorage.variable_content_types
で確認ができるようになっています。
# Rails v6.1
ActiveStorage.variable_content_types
=> ["image/png",
"image/gif",
"image/jpg",
"image/jpeg",
"image/pjpeg",
"image/tiff",
"image/bmp",
"image/vnd.adobe.photoshop",
"image/vnd.microsoft.icon",
"image/webp"]
つまり、変換ができない形式の画像に対してActiveStorage::Blob#variant
を呼んだ時にActiveStorage::InvariableError
が発生するようになっています。
エラーの原因と対策
今回エラーの原因となっていた画像を調べてみると、画像形式がimage/avif
という形式になっており、その画像に対してActiveStorage::Blob#variant
が呼ばれていました。※補足
対策としては、画像を添付したいModelにvaridationを設定することですが、ActiveStorageにはRailsの標準でvalidationを設定することができないっぽいです。
幸いactive_storage_validations
というgemがあるようなので、これを導入してvalidationを設定しておくと良さそう。
(なぜRailsの標準機能としてActiveStorageのvalidationを実装しないのだろうか?)
補足
今回はimage/avif
の画像形式で例外が発生したわけですが、この画像形式は今後普及されていくであろうと言われている次世代型の画像形式ファイルらしいです。
もしやと思い、Rails7.0以降の環境で確認してみるとimage/avif
にも対応していました。
「変換したい画像形式にActiveStorageが対応していない!」というときは、Railsのバージョンアップを検討してみるのも良いかもしれません。
ActiveStorage.variable_content_types
=>
["image/png",
"image/gif",
"image/jpg",
"image/jpeg",
"image/pjpeg",
"image/tiff",
"image/bmp",
"image/vnd.adobe.photoshop",
"image/vnd.microsoft.icon",
"image/webp",
"image/avif", # !!!!
"image/heic",
"image/heif"]