factory_girl question

I am still trying to wrap my head around FG… can someone explain me why I am seemingly having to reload an object to have access to the correct association value which I updated since creating the object with FG. Here is an example (Factory below also):

@person = Factory(:person)
@person.addresses.size.should == 0
address = Factory(:address)
@person.add_address(address)
@person = Person.find(@person.id) # if I dont do this I get the old value, 0, but if I reload I get the right value, 1.
@person.addresses.size.should == 1
@person.addresses[0].person_id.should == @person.id

Factory.define :person do |f|
f.first_name {“MyString”}
f.middle_name {“MyString”}
f.last_name {“MyString”}
end

Factory.define :address do |f|
f.person_id {1}
f.address {“MyString”}
f.zip {“94587”}
f.city {“MyString”}
f.state {“MyString”}
end

David Kahn wrote in post #968158:

I am still trying to wrap my head around FG...

What's to wrap your head around? All it does is create an object with
some associations. If you're finding it confusing, you're most likely
overthinking it.

can someone explain me
why I
am seemingly having to reload an object to have access to the correct
association value which I updated since creating the object with FG.
Here is
an example (Factory below also):

@person = Factory(:person)
@person.addresses.size.should == 0
address = Factory(:address)
@person.add_address(address)

Does add_address save @person ?

Personally, I would do @person.addresses << address , which always seems
to do the right thing.

@person = Person.find(@person.id) # if I dont do this I get the old
value,
0, but if I reload I get the right value, 1.
@person.addresses.size.should == 1
@person.addresses[0].person_id.should == @person.id

You do know that, while this test is useful for getting to know Factory
Girl, it is of no use for an actual application, right? All it's doing
is testing FG and AR functionality that's already well tested.

Factory.define :person do |f|
  f.first_name {"MyString"}
  f.middle_name {"MyString"}
  f.last_name {"MyString"}
end

Factory.define :address do |f|
  f.person_id {1}
  f.address {"MyString"}
  f.zip {"94587"}
  f.city {"MyString"}
  f.state {"MyString"}
end

I don't think you need to use blocks for constant values.

However, once you get FG working, I highly recommend using Faker to
generate the data.

Best,

David Kahn wrote in post #968158:

I am still trying to wrap my head around FG…

What’s to wrap your head around? All it does is create an object with

some associations. If you’re finding it confusing, you’re most likely

overthinking it.

can someone explain me

why I

am seemingly having to reload an object to have access to the correct

association value which I updated since creating the object with FG.

Here is

an example (Factory below also):

@person = Factory(:person)

@person.addresses.size.should == 0

address = Factory(:address)

@person.add_address(address)

Does add_address save @person ?

No, the call does just save the new address. I pass it this way as I want to ensure the person object id gets attached to the new address.

Personally, I would do @person.addresses << address , which always seems

to do the right thing.

@person = Person.find(@person.id) # if I dont do this I get the old

value,

0, but if I reload I get the right value, 1.

@person.addresses.size.should == 1

@person.addresses[0].person_id.should == @person.id

You do know that, while this test is useful for getting to know Factory

Girl, it is of no use for an actual application, right? All it’s doing

is testing FG and AR functionality that’s already well tested.

Right… but when I start having a problem I write more test code, that is how I got here…

Factory.define :person do |f|

f.first_name {“MyString”}

f.middle_name {“MyString”}

f.last_name {“MyString”}

end

Factory.define :address do |f|

f.person_id {1}

f.address {“MyString”}

f.zip {“94587”}

f.city {“MyString”}

f.state {“MyString”}

end

I don’t think you need to use blocks for constant values.

Right, that was an oversight

However, once you get FG working, I highly recommend using Faker to

generate the data.

I 'll try it when I have a chance… thanks

David Kahn wrote in post #968171:

> association value which I updated since creating the object with FG.
> Here is
> an example (Factory below also):
>
> @person = Factory(:person)
> @person.addresses.size.should == 0
> address = Factory(:address)
> @person.add_address(address)

Does add_address save @person ?

No, the call does just save the new address.

So it's not changing @person at all, which means that Rails has no way
of knowing that the association has changed. That's probably why you're
getting the results you are.

I pass it this way as I
want to
ensure the person object id gets attached to the new address.

@person.addresses << address does likewise, but I believe it *does* save
or reload @person.

Best,

David Kahn wrote in post #968171:

association value which I updated since creating the object with FG.

Here is

an example (Factory below also):

@person = Factory(:person)

@person.addresses.size.should == 0

address = Factory(:address)

@person.add_address(address)

Does add_address save @person ?

No, the call does just save the new address.

So it’s not changing @person at all, which means that Rails has no way

of knowing that the association has changed. That’s probably why you’re

getting the results you are.

Thank you, that makes a lot of sense. The fog is clearing.

I pass it this way as I

want to

ensure the person object id gets attached to the new address.

@person.addresses << address does likewise, but I believe it does save

or reload @person.

Right, at least in the past this has worked in Rails 2.

Marnen, you consistently take Rails' hallmark "opinionated software"
up a couple of orders of magnitude :wink: so I'm curious about your
opinion on FG vs Machinist. This isn't flame bait; I really am curious
as I'm deliberating between the two. TIA.

Stan Kaufman wrote in post #968201:

However, once you get FG working, I highly recommend using Faker to
generate the data.

Marnen, you consistently take Rails' hallmark "opinionated software"
up a couple of orders of magnitude :wink:

I'm almost afraid to ask how you meant that... :slight_smile:

so I'm curious about your
opinion on FG vs Machinist. This isn't flame bait; I really am curious
as I'm deliberating between the two. TIA.

I've been using Machinist for personal projects and Factory Girl at my
current job. I think I find Machinist friendlier, but the two libraries
are pretty close at this point.

Best,

Side note about FG usage: I was under the impression that this is
suboptimal for FG because now Factory(:address) generates and invalid
object unless you do something special. I traditionally write this as
like this:

Factory.define :address do |f|
  f.association :person
  f.address {"MyString"}
  f.zip {"94587"}
  f.city {"MyString"}
  f.state {"MyString"}
end

This way if I want an address to test and I don't care about it's
person, then Factory(:address) gives me a valid item. And then if I
do care about the association then we do:

@person = Factory(:person)
@person.addresses.size.should == 0
@address = Factory(:address, :person => @person)
@person.address.size.should == 0
@person.reload.address.size.should == 1

Keep in mind that in this case you don't want to do:

@person = Factory(:person)
@address = Factory(:address)
@person.addresses << @address

Because the second line will generate another, unneeded Person object.

\Peter

@person = Factory(:person)

@person.addresses.size.should == 0

address = Factory(:address)

@person.add_address(address)

@person = Person.find(@person.id) # if I dont do this I get the old value,

0, but if I reload I get the right value, 1.

@person.addresses.size.should == 1

@person.addresses[0].person_id.should == @person.id

Factory.define :person do |f|

f.first_name {“MyString”}

f.middle_name {“MyString”}

f.last_name {“MyString”}

end

Factory.define :address do |f|

f.person_id {1}

f.address {“MyString”}

f.zip {“94587”}

f.city {“MyString”}

f.state {“MyString”}

end

Side note about FG usage: I was under the impression that this is

suboptimal for FG because now Factory(:address) generates and invalid

object unless you do something special. I traditionally write this as

like this:

Factory.define :address do |f|

f.association :person
f.address {“MyString”}

f.zip {“94587”}

f.city {“MyString”}

f.state {“MyString”}

end

This way if I want an address to test and I don’t care about it’s

person, then Factory(:address) gives me a valid item. And then if I

do care about the association then we do:

@person = Factory(:person)

@person.addresses.size.should == 0

@address = Factory(:address, :person => @person)

@person.address.size.should == 0

@person.reload.address.size.should == 1

Keep in mind that in this case you don’t want to do:

@person = Factory(:person)

@address = Factory(:address)

@person.addresses << @address

Because the second line will generate another, unneeded Person object.

Thanks… this helps

ppgengler@prevailhs.com wrote in post #968310:
[...]

Keep in mind that in this case you don't want to do:

@person = Factory(:person)
@address = Factory(:address)
@person.addresses << @address

Because the second line will generate another, unneeded Person object.

Hold it. If there's a habtm relationship between Person and Address,
then Addresses shouldn't even have a person_id. OTOH, if there isn't a
habtm relationship, then the << operation is unnecessary (and I think
it's a syntax error).

So...which is it?

\Peter

Best,

Factory.define :person do |f|
f.first_name {“MyString”}

f.middle_name {“MyString”}
f.last_name {“MyString”}

end

Factory.define :address do |f|
f.person_id {1}
f.address {“MyString”}
f.zip {“94587”}
f.city {“MyString”}
f.state {“MyString”}
end

you pass a block like this if you need reevaluation like when using a rand function or faker, it makes no sense to do it with a fixed value

f.address ’ foo’ is the same as f.address { ‘foo’ }

the first and second address created will have the same value in both cases

f.zip rand(1000) the first and second record created will have the same value

f.zip { rand(1000) } each record will have a unique value

so you should add faker and then

f.city {Faker::Address.city}

will give you a differente city for each record

In his original example Address has a person_id field so I was
assuming a has_many relationship, not a HABTM. However, though I'd
want to reflect on it further, I'm pretty sure it doesn't change
anything here as long as you deal with the relationship name
everywhere and not the ID fields; Rails will just do The Right Thing
(tm) and add/remove records in the join table appropriately.

The << is necessary in the second example to be comparable to his
original example where he wanted to create an @person object, then
create an @address object and have them linked; the @address at first
will point to a different Person object than @person, so using the <<
on the collection will add it (i.e. it will set person_id on @address
to @person.id). It does work BTW, I just tested it again in console
to be sure (and its listed at the top of the added methods here:
http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_many,
and if we care about the HABTM here:
http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_and_belongs_to_many).

I think maybe what you're pointing out though, is that he could just
do:

  @address = Factory(:address)

and then use @address.person?

If that's adequate then that's definitely cleaner (and quicker and
more robust). However, what I read from the OP is that he has a need
to create a Person object first, configured a specific way (although
he didn't have any particular factory overrides, so maybe this is an
incorrect assumption?). ~After~ that object is created he needs an
Address that is linked to it. As such he either needs to 1) create
the Address object with a stub Person, then associate with the one he
wants afterwards (suboptimal, the usage of <<) or 2) pass in the
Person object to the Address factory to link at creation time
(preferred, AFAIK).

\Peter

ppgengler@prevailhs.com wrote in post #968602:

Hold it. If there's a habtm relationship between Person and Address,
then Addresses shouldn't even have a person_id. OTOH, if there isn't a
habtm relationship, then the << operation is unnecessary (and I think
it's a syntax error).

So...which is it?

In his original example Address has a person_id field so I was
assuming a has_many relationship, not a HABTM.

Which means << is invalid, doesn't it?

However, though I'd
want to reflect on it further, I'm pretty sure it doesn't change
anything here as long as you deal with the relationship name
everywhere and not the ID fields; Rails will just do The Right Thing
(tm) and add/remove records in the join table appropriately.

It's has_many, so there's no join table.

[...]

I think maybe what you're pointing out though, is that he could just
do:

  @address = Factory(:address)

and then use @address.person?

No. That's not at all what I'm pointing out.

If that's adequate then that's definitely cleaner (and quicker and
more robust). However, what I read from the OP is that he has a need
to create a Person object first, configured a specific way (although
he didn't have any particular factory overrides, so maybe this is an
incorrect assumption?). ~After~ that object is created he needs an
Address that is linked to it. As such he either needs to 1) create
the Address object with a stub Person, then associate with the one he
wants afterwards (suboptimal, the usage of <<) or 2) pass in the
Person object to the Address factory to link at creation time
(preferred, AFAIK).

That's correct.

Best,

Perhaps I'm not understanding what you mean when you say invalid? Do
you mean that it will generate an exception, or that it isn't a good
way to solve the problem?

\Peter

ppgengler@prevailhs.com wrote in post #968626:

Which means << is invalid, doesn't it?

Perhaps I'm not understanding what you mean when you say invalid? Do
you mean that it will generate an exception, or that it isn't a good
way to solve the problem?

I mean that << isn't defined for has_many, but on reflection I realize I
was wrong. Just forget I said that. :smiley:

\Peter

Best,