Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Populating an association with children in factory_girl

I have a model Foo that has_many 'Bar'. I have a factory_girl factory for each of these objects. The factory for Bar has an association to Foo; it will instantiate a Foo when it creates the Bar.

I'd like a Factory that creates a Foo that contains a Bar. Ideally this Bar would be created through the :bar factory, and respect the build strategy (create/build) used to create the Foo.

I know I could just call the :bar factory and then grab the Foo reference from the new Bar. I'd like to avoid this; in my test case, the important object is Foo; calling the Bar factory seems a bit circuitous. Also, I can see the need for a Foo with multiple Bars.

Is this possible in factory_girl? How do you define this relationship in the parent?

like image 476
Craig Walker Avatar asked May 30 '10 02:05

Craig Walker


2 Answers

The Factory.after_ hooks appear to be the only way to do this successfully. I've figured out a way to maintain the build strategy without duplicating code:

Factory.define :foo do |f|   f.name "A Foo"   f.after(:build) { |foo|     foo.bars << Factory.build(:bar, :foo => foo)   }   f.after(:create) { |foo|     foo.bars.each { |bar| bar.save! }   } end 

The documentation states that after_build will be called before after_create if the :create build strategy is used. If :build is used, then only after_build is called, and everyone is happy.

I've also created an abstracted generally-applicable version at this gist to keep things DRY.

like image 184
Craig Walker Avatar answered Oct 06 '22 19:10

Craig Walker


You can use the association method both ways:

Factory.define :foo do |f|   # ...   f.association :bar end 

If that won't work, you can associate them manually using a callback. Here's an example from one of my apps:

Factory.define :live_raid do |raid| end  Factory.define :live_raid_with_attendee, :parent => :live_raid do |raid|   raid.after_create { |r| Factory(:live_attendee, :live_raid => r) } end 
like image 32
Robert Speicher Avatar answered Oct 06 '22 21:10

Robert Speicher