【Rails】RSpecによるActiveStoregeでアップロードした画像のテスト


はじめに

 RSpecでモデルテストを書いている時にActiveStorageでモデルに関連づけた画像のバリデーションのところでつまづいたのでメモ。
 RSpecとFactoryBotを使用する。(ここではインストールの部分は省略)

やること

音楽レビューアプリのRecordモデルに付けた画像(:jacket)が空の時はエラーを表示する。

モデル

RecordモデルはGenreモデルに紐づいている。

Genreモデルは、(一部省略)

app/models/genre.rb
class Genre < ApplicationRecord
  has_many :records
end

Recordモデルは、(一部省略)

app/models/record.rb
class Record < ApplicationRecord
  belongs_to :genre
  has_one_attached :jacket #一つの画像

  validate :jacket_presence #画像のバリデーション

  def jacket_presence
    unless jacket.attached?
      errors.add(:jacket, 'must be attached')
    end
  end
end

has_one_attached :jacketで一つの画像を持つとし、
jacket_presenceメソッドで画像が付いていない時はエラーメッセージを追加する。
  

テスト用画像の用意

 まずpublicディレクトリにjacketsファイルを追加し、
そこに一つ画像を追加する。

ここではjustin.jpgファイルをpublic/jacketsに追加。
  

FactoryBotを編集

まずはGenreを編集する。

spec/factories/genre.rb
FactoryBot.define do
  factory :genre do
    name { "Pop" }
  end
end

次はRecordを編集する。

spec/factories/record.rb
FactoryBot.define do
  factory :record do
    name { "Justice" }
    release_year { 2021 }
    artist { "Justin Bieber" }

    #genreとのアソシエーションは、
    #genre_id { 1 } でなく、以下のように書く
    genre

    #recordモデル作成後:jacketを関連づける。
    after(:build) do |record|
      record.jacket.attach(io: File.open('public/jackets/justin.jpg'), filename: 'justin.jpg')
    end
  end
end

これでテスト用のモデル作成の準備が完了。
  

テストファイルの編集

Recordのモデルテストを編集する。

spec/models/record_spec.rb
require 'rails_helper'

RSpec.describe Record, type: :model do

  describe 'create new record'do

    before do #テスト用のRecordを作成
      genre = FactoryBot.create(:genre)
      @record = FactoryBot.create(:record)
    end

  #全ての項目があれば有効。
    context 'with a name, release_year, artist, genre, and jacket' do
      it "is valid" do
        record = @record
        expect(record).to be_valid
      end
    end

    #:jacketなしの場合はエラー
    context 'without a jacket' do
      it "is invalid" do
        @record.jacket = nil #:jacketを空にする。
        record = @record

        record.valid?
        #エラーメッセージが追加される。
        expect(record.errors[:jacket]).to include("must be attached")
      end
    end

  end 
end

RecordGenreに紐づいているため先にgenreを作成している。

これでテストできた。