🦁

【Rails】seedを使った画像データの注意点

2023/10/16に公開

チーム開発中にseedを使用して画像データを入れた際に起きたエラーから学んだことを復習します。

seed.rbとは

Railsアプリケーションで使用されるデータベースの初期データを生成するためのファイルです。今回は商品データの初期データを入れる際に発生しました。

商品の初期データ作成時の事例

当初はActiveStorageを使用し、その後は下記の記述で作成をしていました。

model/item.rb
class Item < ApplicationRecord
  has_one_attached :image
end

上記の記述でどのモデルに使用するのかを宣言。
そして、下記のseed.rbへ商品ごとに画像が出るように記述。

seed.rb
genres = ['ケーキ','チーズケーキ',・・・]

items_array = [
  [ 'ショートケーキ','チョコレートケーキ',・・・],
  ['レアチーズケーキ','ベイクドチーズケーキ',・・・],
 ・
 ・
 ]
 
 items_array.each_with_index do |items, i| #iはジャンルIDになる
  items.each_with_index do |item, j|
    Item.create!(
      genre_id: i,
      name: item,
      introduction: "#{item}の説明です。こだわりの味。",
      price: 500,
      is_active: true,
      image: File.open("app/images/item-#{i+1}-#{j+1}.jpg")
    )

最後の行でFile.openを使用し画像データの位置と名前等を指定しましたがErrno::ENOENT: No such file or directory @ rb_sysopen - app/images/item-1-1.jpgというエラーが発生してしまいました。上記のエラーはディレクトリが存在しない、ファイル名が違う等ありますがどれも該当しませんでした。

エラーの原因

上記エラーの原因は、ディレクトリの存在やファイル名ではなくデータベース上の問題でした。
簡単に言うと「each文で繰り返される中で、画像ファイルを表示する前に次の処理が同時に始まり起こるバグ」とのことでした。
これはCloud9の初期設定で導入されるSQLiteというリレーショナルデータベース管理システムのキャパを超えた処理が原因とのことです。

解決方法

次の処理が起こらないよう同期処理に変更し、商品ごとに処理が順番に行われるように設定します。

development.rb
config.active_job.queue_adapter = :inline
# 同期処理に変更させるための記述

そして、今回はActiveStorageを使用するためeach文の最後の記述も変更します。

seed.rb
item.image.attach(io: File.open(Rails.root.join("app/assets/images/item-#{i+1}-#{j+1}.jpg")), filename: "item-#{i+1}-#{j+1}.jpg")

最初の記述方法はActiveStorageを使用しないかつ、商品1つだけの場合の記述方法だったため
今回のActiveStorageを使用し複数商品に対応する場合は上記記述が必要でした。

今回のデータベースに関してはそんなに多発するエラーではないとのことなので初心者で原因を見つけるのは厳しいかと思います。ある程度調べたら早めにメンターさんに相談すること、そして何かを参考にする際にはRailsのバージョン等も含め条件が一致しているかの確認も忘れないようにしようと思いました。

正直、記事にしていてもおおよその理解でしかないエラーでしたが、今回はいい経験だったのでここに書かせていただきました笑

Discussion