LoginSignup
18
14

More than 5 years have passed since last update.

FactoryBotでbelongs_toとhas_manyの関係にあるやつ

Posted at

belongs_toとhas_manyの関係にあるモデルオブジェクトをFactoryBotで作っていて、無限ループになってハマった話と対策。

モデル例

Groupに複数のUserが所属するものとする。モデルはこんな感じになる。

class Group < ApplicationRecord
  has_many :users
end

class User < ApplicationRecord
  belongs_to :group
end

これらをテストする時、FactoryBot.create(:user)とすれば、belongs_toなgroupも自動生成され、FactoryBot.create(:group)した時には、has_manyなuserもが自動生成されるになっているとテスト書くのが楽です。

belongs_to宣言しているモデルUserのFactoryBot

以下のようにbelongs_toの宣言そのまま書くだけでいい。

FactoryBot.define do
  factory :user do
    group
  end
end

これでFactoryBot.create(:user)するとGroupのFactoryBotでGroupを作りUserとひもづけてくれる。

has_many宣言しているモデルGroupのFactoryBot

以下のようにするのが望ましいと思われる。

FactoryBot.define do
  factory :group do
    users {[
     FactoryBot.build(:user, group: nil)
    ]}
  end
end

ポイントは

  • FactoryBot.createでなくbuildであること
  • groupにnilを入れていること

である。

ここを、FactoryBot.create(:user)にしてしまうと、

  • UserのFactoryBotもGroupを生成するようになっている
  • つまりGroupのFactoryBotが呼び出される
  • GroupのFactoryBotもUserを生成しようとする
  • つまりUserのFactoryBotが呼び出される
  • 最初に戻る

という無限ループになります。

よって、

  • FactoryBot.build(:user)を使ってDBへの生成は行わずオンメモリで作る
  • さらにgroupをnilを渡す。これによりGroup自身がDBにINSERTされ、Groupのidが決定した後に、そのidがusersのgroup_idに入る

となるように、FactoryBot.build(:user, group: nil)にしています。

18
14
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
18
14