環境
macOS: Big Sur Ver11.2.2
Rails: 6.0.0
Ruby: 2.6.5
前提
Railsで開発中しており、deviseを使ってユーザー登録関係を実装済み(Userモデル)。
さらに、UserモデルはActiveStorageにより画像を1枚添付できるようになっている(必ず添付しなければならない制約をつけてます)。
モデルのコードはこんな感じで、 has_one_attached と :image属性にpresence: trueが指定されているのがわかります。
class User < ApplicationRecord
extend ActiveHash::Associations::ActiveRecordExtensions
belongs_to :prefecture
belongs_to :category
has_one_attached :image
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
# パスワードは半角英数混合で8文字
validates :password, format: { with: /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]{8}\z/i }
with_options presence: true do
validates :shop_name
validates :address
validates :business_hours
validates :holiday
validates :image
validates :phone_number, format: { with: /\A0[1-9]\d{0,3}[-(]\d{1,4}[-)]\d{4}\z/ }
with_options numericality: { other_than: 0 } do
validates :category_id
validates :prefecture_id
end
end
end
やりたいこと
ユーザーに紐づく画像をトップページに表示させたかったので、サンプルデータを20~30件くらい作って一気に表示させてみようと思いました。
新規登録されたユーザーの画像がトップページにズラッと並ぶ感じです。
試したこと①
seeds.rbに以下のとおり記述。
20.times do |n|
user = User.create!(
shop_name: "お店#{ n + 1 }",
email: "seed#{ n + 1 }@seed.com",
password: "pass1234",
password_confirmation: "pass1234",
category_id: rand(1..10),
prefecture_id: rand(1..47),
address: "仮町仮番地123-1",
business_hours: "9時〜17時",
holiday: "月曜",
phone_number: "090-1234-5678",
image: open("./db/fixtures/seed.jpg")
end
結果、「ファイルが見つからない、、」というエラー。
試したこと②
20.times do |n|
user = User.create!(
shop_name: "お店#{ n + 1 }",
email: "seed#{ n + 1 }@seed.com",
password: "pass1234",
password_confirmation: "pass1234",
category_id: rand(1..10),
prefecture_id: rand(1..47),
address: "仮町仮番地123-1",
business_hours: "9時〜17時",
holiday: "月曜",
phone_number: "090-1234-5678",
)
user.image.attach(io: File.open(Rails.root.join('app/assets/images/test.jpg')),
filename: 'test.jpg')
end
結果、「imageがバリデーションに引っかかりました!」という指摘を受けました。
試したこと③
20.times do |n|
user = User.create!(
shop_name: "お店#{ n + 1 }",
email: "seed#{ n + 1 }@seed.com",
password: "pass1234",
password_confirmation: "pass1234",
category_id: rand(1..10),
prefecture_id: rand(1..47),
address: "仮町仮番地123-1",
business_hours: "9時〜17時",
holiday: "月曜",
phone_number: "090-1234-5678",
user.image.attach(io: File.open(Rails.root.join('app/assets/images/test.jpg')),
filename: 'test.jpg')
end
結果、「userに使っているimageというメソッドはないよ」と怒られました。
解決策
以下の記述方法を発見し、無事に画像データを持つユーザーのサンプルデータを作成できました。
20.times do |n|
user = User.create!(
shop_name: "お店#{ n + 1 }",
email: "seed#{ n + 1 }@seed.com",
password: "pass1234",
password_confirmation: "pass1234",
category_id: rand(1..10),
prefecture_id: rand(1..47),
address: "仮町仮番地123-1",
business_hours: "9時〜17時",
holiday: "月曜",
phone_number: "090-1234-5678",
image: ActiveStorage::Blob.create_and_upload!(io: File.open(Rails.root.join("db/fixtures/seed.jpg")), filename: "seed.jpg")
)
end
最後に
ググって出てきた情報の多くは、画像をユーザーを作成した後からattachする場合のやり方で、自分のようにユーザー作成時点で画像が必須という設計とは前提が異なっていました。
なので3つの方法全てがエラーになったんですね。
ちなみに後から画像をattachする方法は、Railsガイドに書いてあります。
解決策のcreate_and_upload!メソッドはこちらに掲載されています。
あまり見たことがない公式リファレンス?だったので、これは初心者には厳しいな、、と言う印象でした。
この記事が誰かの役に立てば幸いです!
補足
seeds.rb ファイルを編集などして、再度サンプルデータを流すときは、以下のコマンドを実行すればデータベースの中身をリセットしてサンプルデータの流し込みまで一括でやってくれます。
% rails db:reset