ActiveStorageのバリデーションとシードデータの用意


したいこと

ActiveStorageを使って投稿機能を実装している状態で、ファイルの添付を必須にするバリデーションをかけ、それに対応したseedデータの用意したい。

前提

  • Userと1対多の関係にあるPostモデルがある
  • PostにActiveStorageでファイルが紐づけられている

駆け足で説明すると

ターミナル
//UserとPostモデルを作成
$ rails g model User name:string 
$ rails g model Post body:text

※ActiveStorageで追加したいファイル用のカラムは作らなくて大丈夫です。


マイグレーションファイルを編集

db/migrate/xxxxx_create_posts.rb
class CreatePosts < ActiveRecord::Migration[6.0]
  def change
    create_table :posts do |t|
      t.text :body
      #外部キーを追加
      t.references :user, foreign_key: true

      t.timestamps
    end
  end
end

ターミナル
$ rails db:migrate



アソシエーションの記述

/user.rb
class User < ApplicationRecord
  has_many :posts, dependent: :destroy
end
/post.rb
class Post < ApplicationRecord
  belongs_to :user
end



ActiveStorageを導入

ターミナル
$ rails active_storage:install
$ rails db:migrate

Postモデルに画像を1つ添付する設定

/post.rb
class Post < ApplicationRecord
  belongs_to :user
  #追記
  has_one_attached :image
end

:imageの部分はファイルの呼び名で自由に指定してよい

参考


postモデルに画像をの添付を必須にするバリデーションをつける

今回はactivestorage-validatorというgemを使います。
https://github.com/aki77/activestorage-validator



Gemfileを編集

/Gemfile
  gem 'activestorage-validator'
ターミナル
$ bundle

Postモデルに追記

/post.rb
class Post < ApplicationRecord

  has_one_attached :image
  belongs_to :user

  #追記
  validates :image, presence: true, blob: {content_type: :image}
end

エラーメッセージは@post.errors.full_messagesに格納されているので

   <ul>
     <% @post.errors.full_messages.each do |message| %>
       <li><%= message %></li>
     <% end %>
   </ul>

のように書くと表示させることができます。


seedデータを用意する

まず画像データをapp/assets/images/に用意します。

WSL(Windows Subsystem for Linux)で画像を用意したい



次にseedを書いていきます。ここハマりました、ポイントとしては

  • 一度インスタンスを作成してからattachする
  • createではなくnewとsaveを使う
/seed
User.Create!(name: "tony")

post = Post.new(
  user_id: 1,
  body: "foo"
)
post.image.attach(io: File.open("app/assets/images/sample.jpg"), filename: "sample.jpg", content_type: 'image/jpg')
post.save!

参考

【Rails6】seedファイルに画像を追加する(ActiveStorage使用)
Active Storage 3.3 Attaching File/IO Objects

以上です。