Phoenix Rising wrote in post #970888:
Thank you for the reply, Colin. I should have been more descriptive,
so let me elaborate:
Say I have the following models and factories:
# models
class Game < ActiveRecord::Base
validates :name, :presence => true, :uniqueness => true
validates :url, :presence => true, :uniqueness => true
end
class Server < ActiveRecord::Base
belongs_to :game
validates :name, :presence => true
validates :game, :presence => true
end
Server belongs_to Game? Really? Are you sure? If so, why isn't there
a corresponding association on Game? What are you trying to model here?
class Character < ActiveRecord::Base
belongs_to :server # now we can chain character.server.game
validates :name, :presence => true
end
# test/factories.rb
Factory.define :game do |g|
g.name "Foo"
g.url "www.example.com"
end
Factory.define :server do |s|
s.name "Bar"
s.game { |x| x.association(:game) }
end
Factory.define :character do |c|
c.name "Blah"
c.server { |x| x.association(:server) }
end
What's with all the constant data? Use Faker and/or sequences to
generate unique values.
Now, let's say I want to call Factory(:character). It all gets set up
and returned properly as it should. But let's say I have the
following in my factories thereafter:
Factory.define :character2 do |c|
c.name "Bleh"
c.server { |x| x.association(:server) }
end
Again, I worry about :character2. Looks like you're trying to predefine
every record you need in your factory files -- that is, use them like
fixtures -- which is not how factories are supposed to work. The reason
you can define multiple factories for one class is so you can set up
several default configurations (say, ordinary user and admin user), not
so you can define every record in advance.
Logically, I'd expect factory_girl to try to create the :server
object, and if it fails, look for it in the database and set the
assignment of that association to what comes out of the DB if
something already exists. But it doesn't do that.
No, it doesn't. association *always* creates a new record. Of course,
you can override that by doing Factory :character, :server => @server.
But this is not like fixtures, where it retrieves an existing named
fixture. Nor would you want it to be; it would make factories less
flexible.
You can also use AR model methods to find the existing association
record you want.
Instead, FG will
cause an error in tests (not a failure, an actual error) that will say
that the name and url are already taken. After shaking my fists in
the air and pounding my head on the desk, I reply, "YES, I KNOW
they're taken, that's because I want the association on an EXISTING
OBJECT!"
...which is not what the association method does. Find the object and
use it explicitly.
Am I just plain doing it wrong here? Any input you have would be
appreciated. Thank you!
Yes, you are doing it wrong. You're trying to use factories like
fixtures, and (possibly as a result) you're misunderstanding the
semantics of the association method.
Best,