LoginSignup
13
23

More than 3 years have passed since last update.

【Rails】FactoryBotの作り方(アソシエーション、Faker、画像の紐付け)

Last updated at Posted at 2020-03-25

はじめに

今回はFactoryBotという存在は知っているけど、自分で作れって言われたら、ちょっと・・・と思う人に向けて、FactoryBotの作り方を記事にしました。
FactoryBotについての説明は割愛します。

FactoryBotの作り方

基本的な構文はこれです。

FactoryBot.define do
  factory :user do
    first_name { "John" }
    last_name  { "Doe" }
    admin { false }
  end
end

例えば、itemテーブル(商品)を作成するとしたら

  • まず、FactoryBotの決まり文句を書きます。
factories/items.rb
FactoryBot.define do
  factory :item do
  end
end
  • 次に、カラムを列挙します。
factories/items.rb
FactoryBot.define do
  factory :item do
    name {"レモン"}  # {}で囲っているとfactoryが生成された時に評価される
    price {3000}
  end
end

使い方、属性の上書きの仕方

create(:item)
create(:item, name: "リンゴ")

アソシエーションの仕方

例えば、itemとuserが紐づいている場合、以下のように書く。
(userのfactoryBotも作成している必要がある)

factories/items.rb
FactoryBot.define do
  factory :item do
    name {"レモン"} 
    price {3000}
    association :user, factory: :user # アソシエーション
  end
end

association :user, factory: :userの部分は単にuserと省略できる

factories/items.rb
FactoryBot.define do
  factory :item do
    name {"レモン"} 
    price {3000}
    user # アソシエーション
  end
end

画像の紐付けの仕方

itemにimageが紐づいている時を想定します。
itemは必ずimageが紐づいており、imageは必ず紐づいたitemがあります。

先ほどの通り、実装すると、以下のようになりますが、imageを作るときに、itemが必要で、itemはまだ作成されていないので、結論うまくいきません。

factories/items.rb
# これはうまくいかない
FactoryBot.define do
  factory :item do
    name {"レモン"} 
    price {3000}
    user
    image
  end
end

after(:build)を使用する必要があります。
これで、imageを一枚紐づけることができます。

factories/items.rb
FactoryBot.define do
  factory :item do
    name {"レモン"} 
    price {3000}
    user
    after(:build) do |item|
      # carrierwaveの場合
      item.images << build(:image)
      # ActiveStorageの場合
      item.images.attach(io: File.open('spec/fixtures/test_image.jpg'), filename: 'test_image.jpg', content_type: 'image/jpg')
    end
  end
end
factories/images.rb
# carrierwaveの場合のみ必要
FactoryBot.define do
  factory :image do
    image { File.open("#{Rails.root}/public/images/test_image.jpg") }
  end
end

after(:build)で保存される直前に処理を実行でき、複数のfactoryを同時に生成することができる

Fakerの使い方

FactoryBotと良く一緒に使われるのがFaker。
Fakerを使うメリットは、ランダムな文字列を生成してくれるところにある。
例えば、deviseを用いたユーザログインでは、emailがすでに登録されていたらそのemailを使うことができない。

以下のようなFactoryを作成してしまうと

factories/users.rb
# これはうまくいかない
FactoryBot.define do
  factory :user do
    name {"テストユーザー"}
    email {"test@hello.com"} 
  end
end

生成する際に、エラーが起こる

john = create(:user, name: "John")
kevin = create(:user, name: "kevin") # emailが重複して作成できない!!

Fakerを使用すると、ランダムに生成してくれて、エラーが起きない。

factories/users.rb
FactoryBot.define do
  factory :user do
    name {"テストユーザー"}
    email { Faker::Internet.free_email } 
  end
end
13
23
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
13
23