LoginSignup
9
5

More than 5 years have passed since last update.

Shrineのimage_dataを含むモデルのFactoryの作り方

Posted at

(編集しようとしたら誤って削除してしまったので再投稿しました)

railsの画像アップロードライブラリshrineを用いた場合の、FactoryBotのFactoryの書き方について悩んだポイントがあったので書いておきます

前提

登場するModel

  • Area
column type memo
name string require
  • Shop
column type memo
area bigint require
logo bigint require
name string require
  • Logo
column type memo
area bigint require
name string require
image_data text require

Area has_many Shop
Area has_many Logo
Shop belongs_to Logo

各Shopはエリアに登録されているロゴを使用できるイメージです。

悩んだこと

logoのファクトリーのimage_data カラムをどう書くべきなのか悩みました。

spec/factories/logos.rb
FactoryBot.define do
  factory :logo do
    area
    sequence(:name) { |i| "logo#{i}" }
    image { #この部分!! }
  end
end

もともとは↓のように書いていたのですが、これだとlogoのテストデータが作成されるたびにファイルへアクセスするためRSpec全体の実行時間に大きな影響を与えていました。


image { File.open("#{Rails.root}/spec/fixtures/img/example.png") }

RSpec実行時間

Factory追加前→ 27s
追加後 →1min 3s

shopが作られるたびにFactoryBotによってlogoも自動で作られるのだから遅くなるのは当たり前ですね

試したこと

適当な文字列をつっこむ

image_data { 'sample' }

結果
imageを実際に使うテストにて

JSON::ParserError:765: unexpected token at 'sample'

それはそう。。

fixture_file_upload使ってみる

fixture_file_uploadについて

この記事ではfixture_file_upload使ったらFile.openより相当早い結果になっているので期待大!

image { fixture_file_upload("#{Rails.root}/spec/fixtures/img/example.png", 'img/png') }

結果
テストはすべてpass!
ただし

Finished in 1 minute 9.24 seconds (files took 15.67 seconds to load)

File.openのときと変わらないくらい時間かかってる。。
使い方がおかしい?

最終的に

ファイルアクセスではなく架空のcacheを作成してみる

Shrineのuploaded_fileメソッドを用いてキャッシュの状態でファイルが上がっていることにする作戦

factory :logo do
    area
    sequence(:name) { |i| "logo#{i}" }
    image_data { Shrine.uploaded_file(
      'id' => SecureRandom.hex(8),
      'storage' => 'cache',
      'metadata' => { 'mime_type' => 'image/jpeg', 'size' => 1.megabyte }).to_json }
  end

結果

Finished in 31.04 seconds

いいじゃん!!

参考にしたページ
https://stackoverflow.com/questions/44812403/rails-testing-file-upload-validation-shrine-gem-at-model-spec

補足

最終型において image ではなく image_data を使っている理由について書きます。

はじめはFile.openと同じように下記のように書いていたんですが、

image { Shrine.uploaded_file(
      'id' => SecureRandom.hex(8),
      'storage' => 'cache',
      'metadata' => { 'mime_type' => 'image/jpeg', 'size' => 1.megabyte }).to_json}

結果
imageを実際に使うテストにてエラーが起きる

No such file or directory @ rb_sysopen - /usr/src/app/public/uploads/cache/675ce0d849e8a5f8

ファイルをあげようとしてるんだけど、そんなファイルはないよと言われているように見えます。

shrineを用いた実装において、

image_data → 添付ファイルの全情報がjson形式で保存されるためのDBカラム
image      → 添付ファイルをハンドリングするためのvirtualなattribute

ということは

image_data → upload済みのファイル情報を入れる。
image      → uploadしたいファイル情報を入れる。

最終形では、Shrine.uploaded_fileでファイルが上がっていることにしていたのでimage_dataに入れるのが正解ということでした

9
5
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
9
5