problem setting conditional values for associations

534 views
Skip to first unread message

Morgan Whitney

unread,
May 7, 2012, 1:25:13 PM5/7/12
to factor...@googlegroups.com
With the old factory girl, we had quite a few factories like this:

 Factory.define :thing do |t|
   t.project {|f|  if user = f.get(:user)
                     f.association(:project, :account => user.account)
                   else
                     f.association(:project)
                   end}
 
   t.user    {|f| f.association(:user, :account => f.project.account)}
 end

This allowed us to do any of the following:

factory.create(:thing)
factory.create(:thing, user: a_user)
factory.create(:thing, project: a_project)

and get a valid Thing back.  This is important, because a Thing is required to have both a user and a project, and both the user and the project have to belong to the same account to be valid.  My attempts to refactor have been unsuccessful.  Here is the latest incarnation:

factory :thing do
  project { if user
              FactoryGirl.create(:project, corporate_account: user.account)
            else
              FactoryGirl.create(:project)
            end }
  user    { FactoryGirl.create(:user, account: project.account) }
end

This is what I get when I try to create it:

> FactoryGirl.create(:thing)
SystemStackError: stack level too deep

Is there a different approach that I should be taking here? Is there a better practice here I should know about?


Joe Ferris

unread,
May 7, 2012, 6:10:33 PM5/7/12
to factor...@googlegroups.com
Hey,

Newer versions of factory_girl will try to evaluate dynamic attributes when you reference them before they're evaluated. This is usually a good thing, because it means that attribute order, inheritance, and overrides are no longer confusing to string together. In your case however, it looks like you were taking advantage of the "dumb" nature of earlier versions of factory_girl, so the upgrade didn't work well for you.

If I understand correctly, you're trying to see if the test passed a user to the Thing factory. Is that right?

If so, there's some internal stuff in factory_girl that you could use to get the job done:

    factory :thing do
      project do
        if __override_names__.include?(:user)
          FactoryGirl.create(:project, corporate_account: user.account)
        else
          FactoryGirl.create(:project)
        end
      end
      user { FactoryGirl.create(:user, account: project.account) }
    end

Please keep in mind that __override_names__ isn't part of the public API and might go away or be renamed in a future version. We'll try to come up with a better solution for this specific case.

-Joe
--
Individuals over processes. Interactions over tools. Agile Rails training from thoughtbot, the makers of Clearance, Shoulda, & Factory Girl:
http://thoughtbot.com/services/training
 
You received this message because you are subscribed to the "factory_girl" mailing list.
To post to this group, send email to factor...@googlegroups.com
To unsubscribe from this group, send email to
factory_girl...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/factory_girl?hl=en

Henrik Nyh

unread,
May 25, 2012, 1:23:51 PM5/25/12
to factor...@googlegroups.com
Thanks! We've been using it something like this: https://gist.github.com/2788182
Reply all
Reply to author
Forward
0 new messages