views:

454

answers:

2

I have an issue where I have a parent model Foo, which both has_many :bars and has_many :bazes. Finally, I also have a join model BarBaz which belongs_to :bar and belongs_to :baz. I want to validate all bar_bazes so that its bar and baz both belong to the same foo. But I can't seem to figure out a way to define a factory for this model that would be valid.

Factory.define(:bar) do |bar|
  bar.association(:foo)
end

Factory.define(:baz) do |baz|
  bar.association(:foo)
end

Factory.define(:bar_baz) do |bar_baz|
  baz_bar.association(:foo)
  baz_bar.association(:bar)
  baz_bar.association(:baz)
end

I get an invalid record error when I try to create the latter, because the bar and baz factory_girl tries to associate it each have their own foo. Am I screwed?

+2  A: 

So after hours of beating my head against this issue, I think I finally have a solution. It's pretty insane though, so hopefully someone else can still show me where I'm being stupid.

Factory.define :foo do |foo|
end

Factory.define :bar do |bar|
end

Factory.define :baz do |baz|
end

Factory.define :foo_with_baz do |foo|
  foo.after_create { |foo| Factory(:baz, :foo => foo) }
end

Factory.define :bar_baz do |bar_baz|
  bar_baz.bar {|bar| bar.association(:bar, :foo => Factory(:foo_with_baz))
  bar_baz.after_build {| bar_baz| bar_baz.baz_id = bar_baz.foo.bars.first.id }
end

The key issue being that there needs to be a foo in the database already you can get at through the factories alone, since you can use local variables or arbitrary ruby code in factories.rb (as far as I can tell).

floyd
@floyd, this is pretty impressive work. Great job
Trip
Well, it can't be that great because after coming back to it after a few months I can't remember what the hell I was doing. :)
floyd
A: 

The insaneness of creating factories with deeply nested associations led me to create fixie which lets you create test records using ActiveRecord. It runs during the db:test:prepare step. I use it to eliminate the need for fixtures. You can continue to use factories for easier-to-build objects.

Luke Francl
I really like that, but why can't we make our factory solution allow arbitrary Ruby code in Factory definitions?
floyd
You can to some extent. The trick you need to work around is that factories are called many times and need to produce a valid object each time. This gets messy with associations.
Luke Francl