woshidan's loose leaf

ぼんやり勉強しています

FactoryGirlでfactory定義のブロックでデフォルトのアソシエーションを書くとその都度関連先のレコードが作成される

FactoryGirlでassociationを使うとき、

  factory :item_one, class: Item do
    name 'first'
    association :user, factory: :user_one
    memo 'memo'
    category_id 1
  end

のようにassociationの部分の列を書くと、アソシエーションが含まれているfactoryを使ってレコードを作成する度、 この場合は、item_oneのfactoryでcreateする度、user_oneのfactoryから出来るレコードも作成されます。

それだけだと、これでいいのですが、以下のように、 user_oneのfactoryで作成したレコードに複数のitemのレコードをひもづけたい場合はやや困ります。

FactoryGirl.define do
  factory :item_one, class: Item do
    name 'first'
    association :user, factory: :user_one
    memo 'memo'
    category_id 1
  end

  factory :item_two, class: Item do
    name 'second'
    association :user, factory: :user_one
    memo 'memomemo'
    category_id 1
  end
end

レコードが生成されるのがいやなら、strategy: :buildの指定を使えばいいのでは、
感あったのですが、:item_oneと:item_twoのfactoryから作ったレコードには
同じusersのレコードのidを持っていて欲しかったのです。

データベースにusersのレコードが1件だけ保存されており、
その保存されたレコードのidをitemのレコードが持っていてほしかったので、
strategy: :buildは使いたくなかったのです。

こういうとき、どう綺麗に書いたら綺麗なのか分からなかったので、とりあえず、手で書いたのを投下します。

  def setup
    @user_one = create(:user_one)
    @item_one = create(:item_one, user: @user_one)
    create(:item_two, user: @user_one)
    create(:item_three, user: @user_two)
  end

fixturesは当然と言えば当然なのですが




のように書いても新しくレコードが作成されるわけじゃないので、少しびっくりしました。

以下、動作確認用コードを置いてきます。

FactoryGirl.define do
  factory :item_one, class: Item do
    name 'first'
    association :user, factory: :user_one
    memo 'memo'
    category_id 1
  end

  factory :item_two, class: Item do
    name 'second'
    association :user, factory: :user_one
    memo 'memomemo'
    category_id 1
  end

  factory :item_three, class: Item do
    name 'third'
    association :user, factory: :user_two
    memo 'memomemomemo'
    category_id 1
  end
end
FactoryGirl.define do
  factory :user_one, class: User do
    first_name '太朗'
    last_name '田中'
    age 20
    postal_code '111-1111'
    address_1 '東京都どこか区'
    address_2 'そのへん町1-2-3'
    address_3 'アパート適当456'
  end

  factory :user_two, class: User do
    first_name '次郎'
    last_name '佐藤'
    age 30
    postal_code '222-2222'
    address_1 '何とか県いずこ市'
    address_2 'あのへん町3-2-1'
    address_3 ''
  end
end
  def setup
    @user_one = create(:user_one)
    puts "after @user_one = create(:user_one) User.count #{User.count}"
    create(:user_two)
    puts "after create(:user_two) User.count #{User.count}"
    @item_one = create(:item_one)
    puts "after @item_one = create(:item_one) User.count #{User.count}"
    create(:item_two)
    puts "after create(:item_two) User.count #{User.count}"
    create(:item_three)
    puts "after create(:item_three) User.count #{User.count}"
  end
  def setup
    @user_one = create(:user_one)
    puts "after @user_one = create(:user_one) User.count #{User.count}"
    create(:user_two)
    puts "after create(:user_two) User.count #{User.count}"
    @item_one = create(:item_one, user: @user_one)
    puts "after @item_one = create(:item_one, user: @user_one) User.count #{User.count}"
    create(:item_two, user: @user_one)
    puts "after create(:item_two, user: @user_one) User.count #{User.count}"
    create(:item_three, user: @user_two)
    puts "after create(:item_three, user: @user_two) User.count #{User.count}"
  end