LoginSignup
2
0

More than 1 year has passed since last update.

【Rails】Fromオブジェクトパターンを使用したActiveStorageの拡張子バリデーションを設定する方法

Last updated at Posted at 2022-08-16

大阪でRailsを中心に学習している薬剤師エンジニア(初学者)こと、ヨマ(@yoma_2003)です!
Fromオブジェクトパターンを使用したActiveStorageの拡張子バリデーションを設定する方法をまとめます。

※おことわり※
断定口調でまとめますが、初学者であるため間違い等あればご指摘頂けると嬉しいです。

はじめに

やりたいこと

以下の様にPostモデルとCommentモデルに同時にデータを登録するため、PostCommentモデルというFormオブジェクトを作成した時、
PostCommentモデル(Formオブジェクト)において、Postモデルで保存する画像データに拡張子のバリデーションを設定したい。

formobj.png

post_comment.rb
class PostComment
  include ActiveModel::Model
  attr_accessor :post_name, :image, :comment_name, :content

  def save
    post = Post.create(name: post_name, image: image)
    Comment.create(name: comment_name, content: content, post_id: post.id)
  end
end
post.rb
class Post < ApplicationRecord
  has_one_attached :image
  has_many :comments
end
comment.rb
class Comment < ApplicationRecord
  belongs_to :post
end

結論

PostCommentモデル(Formオブジェクト)に以下の様にバリデーションを自作する。

post_comment.rb
validate :post_image_validation

def post_image_validation
  if !self.image.content_type.in?(%('image/jpeg image/png'))
    self.errors.add(:image, 'は JPEG 形式または PNG 形式のみ選択してください')
  end
end

解説

1. バリデーションを自作する方法

ActiveStorageにはバリデーション機能が存在せず、以下の様に自作します。

モデル内
validate :post_image_validation

def post_image_validation
  #バリデーション処理を定義
end

2. モデルから作成されるインスタンスの画像データオブジェクトの違いについて

モデルから作成されるインスタンスの画像データにはcontent_typeカラムというファイル形式を格納する場所があり、ここに指定のファイル形式が含まれているかどうかを検証しますが、「ActiveStorageとアソシエーションを組む通常のモデルのインスタンス」と「Formオブジェクトのインスタンス」では作成される画像データのオブジェクト形式が異なり、格納されている場所も異なります。

投稿データをPostモデルのみに保存する場合

model.png

※PostモデルはActiveStorageとアソシエーションを組む、通常のモデル

作成された画像データ
ActiveStorageクラスのオブジェクトとしてPostモデルインスタンスのimageカラム内のblobカラムに格納されます。

pry(#<PostsController>)> @post.image.blob

=> #<ActiveStorage::Blob:0x00007fa8ab1b5458
   id: nil,
   key: nil,
   filename: "test.png",
   content_type: "image/png",
   metadata: {"identified"=>true},
   byte_size: 5000,
   checksum: "・・・",
   created_at: nil>

Postモデルにバリデーションを設定すればよいので、以下の様にバリデーションを設定します。

post.rb
  validate :post_image_validation

  def post_image_validation
    if !self.image.blob.content_type.in?(%('image/jpeg image/png'))
      self.errors.add(:image, 'は JPEG 形式または PNG 形式のみ選択してください')
    end
  end

Formオブジェクトを経由してPostモデルに保存する場合 (今回の場合)

formobj.png

※PostCommentモデルはFormオブジェクト

作成された画像データ
ActionDispatchクラスのオブジェクトとしてPostCommentモデルインスタンスのimageカラムに格納されます。

pry(#<PostsController>)> @post_comment.image

=> #<ActionDispatch::Http::UploadedFile:0x00007fa8ab1ed290
   @content_type="image/png",
   @headers="Content-Disposition: form-data; name=\"post_comment[image]\"; filename=\"test.png\"\r\nContent-Type: image/png\r\n",
   @original_filename="test.png",
   @tempfile=#<File:/var/folders/mf/000000000000/T/RackMultipart20220816-6841-0000.png>>

※ActiveStorageとのアソシエーションを定義していないPostCommentモデルでは、アップロードされた画像データはActionDispatchオブジェクトとしてインスタンス内にデータが格納されます。

PostCommentモデルにバリデーションを設定すればよいので、以下の様にバリデーションを設定します。

post_comment.rb
validate :post_image_validation

def post_image_validation
  if !self.image.content_type.in?(%('image/jpeg image/png'))
    self.errors.add(:image, 'は JPEG 形式または PNG 形式のみ選択してください')
  end
end

おわりに

今回、ActiveStorageのバリデーションに関する記事はいくつか見つけられましたが、Formオブジェクトでのバリデーションに関する記事はあまりみつからなかったためまとめてみました。
正直、タイトルはギリギリ語弊がありそうな感じがします、、、

参考

2
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
2
0