(編集しようとしたら誤って削除してしまったので再投稿しました)
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 カラムをどう書くべきなのか悩みました。
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使ったら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
いいじゃん!!
補足
最終型において 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に入れるのが正解ということでした