0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ActiveStorage::InvariableErrorが出た時の対処法と画像以外のファイルが投稿されない様にする技

Posted at

まず初めに

ActiveStorageを使って画像を管理していました。
提出する前はいける!と思っていたのですが、欠点を見つけてもらいまして
その不具合というのが
画像ファイル以外のものを投稿し、variant(resize_to_limit: [width, height])
とこのようにリサイズができない時に出るエラーです。

エラー名: ActiveStorage::InvariableError
もっと詳しくいうとActiveStorageが画像の変数
(今回の場合:画像のサイズや形状)を変更できないときに発生するエラーです。

スクリーンショット 2023-06-18 17.09.38(2).png

あれ?なぜでしょうしっかりと<%= f.file_field :image, accept: "image/*" %>
この様にしっかりと画像以外のファイルは投稿できないようにフィルターをかけていました。

本当に流石でした。フィルターかけても画像ファイル以外の物を投稿できてしまうのですね。。

解決策

クライアント側だけでなくサーバーサイド側でもバリデーション(検証)をつける

まずは、has_oneまたはmany_attachedで関連付けているモデルに
画像以外のファイルは受け付けないようにカスタムバリデーションを記述しファイルを投稿する前に
検証するようにする。

model
# frozen_string_literal: true

class Product < ApplicationRecord
  has_one_attached :image

  validate :image_type

  private

  # 画像投稿時のバリデーション
  def image_type
    if image.attached? == false
      errors.add(:image, 'を選択してください')
    elsif !image.blob.content_type.start_with? 'image/' 
      errors.add(:image, '以外の種類のファイルは投稿できません!拡張子が.jpg,.jpeg,.png,.gif,.bmp.tiff,.svg,.ico,.webpである必要があります。')
    end
  end
end

エラーメッセージの部分が変なのはja.ymlで自分でimageを画像と日本語化しているからです
なのでerrors.add(:image, 'を選択してください')これは画像を選択してください
エラーメッセージが出せるようになります。

image_typeメソッドの中身

image.attached?でファイルが選択されているかいないかチェックをします。

falseなので選択されていない状態です。

よってここでDBのNOTNULLの制約と同じことができます。

次に!image.blob.content_type.start_with?この部分は
ファイルが画像ファイルでない時に起こすことができるエラーメッセージです。

深掘りするとRubyの文字列メソッドであるstart_with?を使用して、

Active Storageのblobのcontent_typeが指定した文字列で始まるかどうかをチェック!

image.blob.content_typeはActive Storageに保存されたファイル
(この場合、image)のMIMEタイプを返す。

よってアップロードされたファイルが画像ファイルかどうかをチェックしていて
trueになれば画像ファイルだということを意味しています。
今回は画像ファイルでない時にエラーメッセージが出て登録できないようにするので
!をつけて反転しています。

そして最後にvalidate :image_typeと設定することで自分で作ったカスタムバリデーションが設定
できるということになります!

次にビュー側で一番最初にvariantメソッドを呼び出す時にチェックする必要がある!

私の場合は、編集画面でプレビューする時です

<% if product.image.blob.content_type.start_with? 'image/' %>
  <%= image_tag(product.image.variant(resize_to_limit: [200, 200]) %>
<% end %>

これらを設定すると画像を選択するときに画像ファイル以外は選択できないフィルターをかけ
万が一投稿されても、サーバー側でも検証をしているため保存する前に
バリデーションエラーを表示することができます!!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?