備忘録です。
ActionView::Template::Error (ActiveStorage::InvariableError)の原因と、その対処法について仮説・検証しました。
エラー背景・経緯
デプロイしたアプリの動作確認を行うことにしました。今回は画像がアップロードされているかどうかを、簡易的に手動で確認したいため、単体テストや結合テストを行わずに動作確認を行うことにしました。
今回は周りの友達に動作確認テストの協力をしてもらいました。
協力内容としては、画像を投稿できるフォームにファイルを添付して、投稿したファイルがビューに表示できるかどうかを確認して欲しいと依頼しました。
エラー内容
協力者である友達から、画像ファイルを添付したと報告をもらったので、デプロイしたアプリの詳細画面を確認しました。すると、"We're sorry but something went wrong"と表示されてしまいました。
まずは、ターミナルでログとそのエラー内容を確認しました。(今回はheroku)
% heroku logs --tail
(中略)
ActionView::Template::Error (ActiveStorage::InvariableError)
34: <div>
35: 画像
36: </div>
37: <%= image_tag @question.image.variant(resize: '200x200'), class: 'question-image' if @question.image.attached? %>
38: <% end %>
39:
40: <%= render 'shared/error_messages', model: @comment %>
app/views/questions/show.html.erb:37
調べたこと
エラー内容に関する記事を調べてみました。このエラーを解決する鍵は「variable?メソッドを使って、blobが変数であるかどうかを区別する」とのことでした。
ここで言う変数は添付される画像ということになりますが、正しい変数(画像)が与えられているかが鍵となることがわかりました。
「そもそもvariable?とはなんぞや」
ということでネットで調べてみると、variable?を使ってTrueの時のみ画像を呼び出せる様にする時に使うとのこと。そして、ActiveStorage.variable_content_typesメソッドと組み合わせることで、指定した拡張子のみの画像を添付できる様に制限をかけることがわかりました。
仮説
そもそも、友達が投稿したファイルは画像ファイルではない、もしくはactive_storageがサポートしている拡張子の画像ではない。という仮説を立てました。
行ったこと
友達に画像以外を載せた可能性を聞いてみました。すると、「画像も他の拡張子のファイルも混在しているファイルの中からテキトーに確認せずに添付した」と回答が返ってきました。つまり、画像以外が添付されている可能性大です。
友達から聞いた内容と、自分で立てた仮説をもとに、自分で誤った拡張子のファイルを添付し保存ができるかどうか、詳細ページはエラーになるかどうかを試しました。
結果
友達の時と同様に、全く関係のない拡張子でデータの保存ができました。そして、詳細ページに遷移すると同様に"We're sorry but something went wrong"という表示になりました。
つまり「正しい拡張子のファイルが送信されていなかった」ということがわかりました。
今後は特定の拡張子以外の保存ははじけるように、ActiveStorage.variable_content_typesメソッド等を使用して、今回の様なエラーが起きない様にします。
補足
テストをしていく段階で、画像の拡張子が.heicだとアップロードできない場合がありました(できる場合もありましたが、原因は不明です)。
参考記事2番目の記事に記載されている通りですが、現在は.heic拡張子のファイルのサポートはしていないみたいですので、避けた方が吉 or heicだけをはじく記述をした方が良いかもしれないですね。
英語の記事読むのはかなり重要ですね
参考記事
https://edgeapi.rubyonrails.org/classes/ActiveStorage/InvariableError.html
https://stackoverflow.com/questions/60686249/activestorageinvariableerror-in-homeindex
https://qiita.com/xusaku_/items/36a61e35b6cd863bbf9d