How to force FactoryGirl to create parent before creating factory?
Asked Answered
W

1

5

I have an Event model that, when saved, updates some attributes on the parent User.

class User
  has_many :events
end

class Event
  belongs_to :user
  before_save :update_user_attributes

  validates :user, presence: true

  def update_user_attributes
    self.user.update_attributes(hash_of_params)
  end
end

This works fine most of the time — a User must exist and be logged in before they can interact with an Event.

But my test suite is causing problems, specifically the event factory.

FactoryGirl.define do
  factory :event do
    user
  end
end

It seems that, due to the order FactoryGirl builds the Event, the User is not available at the time the Event is created, causing update_user_attributes to fail.

This means that

create(:event)
# ActiveRecord::RecordNotSaved:
# Failed to save the record

but

build(:event).save

passes without errors

There are a number of ways I could prevent the error being raised, e.g., check that user.persisted? in the update_user_attributes method, or run the callaback after_save. But my question specifically relates to FactoryGirl.

Given the above factoy, is there a way to force the associated User to be created before creating the Event?

Woodhouse answered 4/4, 2017 at 10:20 Comment(0)
P
9

You can write callbacks in FactoryGirl:

FactoryGirl.define do
  factory :event do
    user

    before(:create) do |event|
      create(:user, event_id: event.id)
    end
  end
end

Here is docs link

Also there is an article on thoughtbot about FG callbacks

Peavey answered 4/4, 2017 at 10:58 Comment(2)
thanks @martin, this works when an event has many users. but I can't figure out how to create a parent and then user the parent's id in the event factory. it would need to be something like` before(:create) do self.user_id = create(:user).id end`. But I can't seem to figure out the correct syntax.Woodhouse
@AndyHarvey, before(:create) do |event| event.user = create(:user) end I supposeIrruption

© 2022 - 2024 — McMap. All rights reserved.