Stumped on this association problem

16 views
Skip to first unread message

Bill Kocik

unread,
May 16, 2009, 2:58:31 AM5/16/09
to factory_girl
I have these in my factories.rb file currently:

Factory.define :user, :default_strategy => :build do |f|
f.groups {|groups| [groups.association(:group)]}
f.default_group {|d| d.association(:group)}
end

Factory.define :group, :default_strategy => :build do |f|
f.sequence(:name) {|n| "Test Group #{n}"}
end

My user model states these associations:
has_many :groups, :include => [:members]
belongs_to :default_group, :class_name => 'Group'

The problem is that at a later point my code needs to figure out which
of user.groups matches user.default_group. This comes back as nil,
because user.groups is returning the group from the first association
call in the user factory, and user.default_group returns the group
from the 2nd association call - so the user's default group is not in
their groups as it is in the live code.

How can I get my user.default_group association to be something that
came out of my groups association call?

Ryan Angilly

unread,
May 17, 2009, 12:37:47 PM5/17/09
to factor...@googlegroups.com
Like this:


Factory.define :user, :default_strategy => :build do |f|
 f.groups {|groups| [groups.association(:group)]}
 f.default_group {|d| d.groups.first}
end

Bill Kocik

unread,
May 17, 2009, 12:47:34 PM5/17/09
to factor...@googlegroups.com
On Sun, May 17, 2009 at 12:37 PM, Ryan Angilly <ang...@gmail.com> wrote:
> Like this:
>
> Factory.define :user, :default_strategy => :build do |f|
>  f.groups {|groups| [groups.association(:group)]}
>  f.default_group {|d| d.groups.first}
> end

Ahh. I didn't realize the variable in the block stood for the object
being instantiated in the factory. That makes some sense, but with
that in place, when the user instance it creates does this:

_groups = self.groups
_default_group = _groups.select{|g| g == self.default_group}.first

...the _default_group var remains nil, which has been my problem all
along. Although outside of testing this code works fine.


--
Bill Kocik

http://bkocik.net

Ryan Angilly

unread,
May 17, 2009, 1:00:02 PM5/17/09
to factor...@googlegroups.com
ActiveRecord == is written like this:

2815       # Returns true if the +comparison_object+ is the same object, or is of the same type and has the same id.
2816       def ==(comparison_object)
2817         comparison_object.equal?(self) ||
2818           (comparison_object.instance_of?(self.class) &&
2819             comparison_object.id == id &&
2820             !comparison_object.new_record?)
2821       end


So if two objects are new records, they will never be considered equivalent.  So in your case, select{|g| g == self.default_group} is always returning an empty array.  Your options are to change your default strategy to create (in which case the ids will match), or write your own comparison method for the model.

Cheers,
Ryan

Bill Kocik

unread,
May 17, 2009, 1:11:10 PM5/17/09
to factor...@googlegroups.com
On Sun, May 17, 2009 at 1:00 PM, Ryan Angilly <ang...@gmail.com> wrote:
> ActiveRecord == is written like this:
>
> 2815       # Returns true if the +comparison_object+ is the same object, or
> is of the same type and has the same id.
> 2816       def ==(comparison_object)
> 2817         comparison_object.equal?(self) ||
> 2818           (comparison_object.instance_of?(self.class) &&
> 2819             comparison_object.id == id &&
> 2820             !comparison_object.new_record?)
> 2821       end
>
>
> So if two objects are new records, they will never be considered
> equivalent.

Except for the part before the or, which is "if the
+comparison_object+ is the same object". In my case they are the same
object (or, at least, that's what I'm trying to achieve).

>  So in your case, select{|g| g == self.default_group} is always
> returning an empty array.  Your options are to change your default strategy
> to create (in which case the ids will match)

I changed it to create for both the user and group factories, and I'm
still getting the same result.

This is why I'm so stumped. It seems like this should be working, and
the live code works fine, but I can't get the test to work to save my
life.

Bill Kocik

unread,
May 17, 2009, 1:38:45 PM5/17/09
to factor...@googlegroups.com
At this point I believe I've determined that the solution Ryan
proposed is actually doing the right thing, but somewhere in the chaos
my model's observer is being invoked and taking over assignment of the
default group. I'll take this offline now and beat my head against the
walls I've created for myself.

Thanks for the help...

Ryan Angilly

unread,
May 17, 2009, 1:47:52 PM5/17/09
to factor...@googlegroups.com
Cool, but I was wrong about two new_record?'s never being equivalent.  equal? keys off of the object id (not the AR::Base id) so if they are the same object then == will work.

For example:

Event.first.equal? Event.first  #=> false, because Event.first creates a new ruby object
a = Event.first
b = a
a.equal? b  #=> true, because a and b are references to the same ruby object.


I think you knew that, Bill, but just wanted it in here for the people that find this on google.
Reply all
Reply to author
Forward
0 new messages