FactoryGirl problems with has_one and belongs_to associations
Asked Answered
P

1

6

I have been fighting with my associations for 3 solid days and don't know where else to turn. I'm sure the problem is very simple, but I'm fairly new to Ruby on Rails and this has me stumped...

I've created a User model which holds all of the login credentials for Devise authentication. I have another Profile model which holds all of the users' settings (first name, etc..). Lastly I have an Address model which uses polymorphic associations which is associated to the Profile.

The User has_one Profile. The Profile belongs_to User and has_one Address. The Address is a polymorphic association which enables other models in my application to have an address associated with them.

At one point, I had all of my FactoryGirl definitions working, but I was troubleshooting a accepts_nested_attributes_for problem and added an after_initialize callback for building the user's profile, and the profile's address. Now my factories have a circular reference to each other, and my rspec output is riddled with:

stack level too deep

Since I've modified my configurations so much over the last few days, I feel it's best to just stop and ask for help. :) That's why I'm here. If anybody could help me with this, I'd really appreciate it.

Here are my factory configurations:

User Factory

FactoryGirl.define do
  sequence(:email) {|n| "person-#{n}@example.com"}
  factory :user do
    profile
    name 'Test User'
    email 
    password 'secret'
    password_confirmation 'secret'
    # required if the Devise Confirmable module is used
    confirmed_at Time.now
  end
end

Profile Factory

FactoryGirl.define do
  factory :profile do
    address
    company_name "My Company"
    first_name "First"
    last_name "Last"
  end
end

Address Factory

FactoryGirl.define do
  factory :address do
    association :addressable, factory: :profile
    address "123 Anywhere"
    city "Cooltown"
    state "CO"
    zip "12345"
    phone "(123) 555-1234"
    url "http://mysite.com"
    longitude 1.2
    latitude 9.99
  end
end

Ideally, I'd like to be able to test each factory independently from each other. In my User model tests, I'd like to have a valid factory like so:

describe "user"
  it "should have a valid factory" do
    FactoryGirl.create(:user).should be_valid
  end
end

describe "profile"
  it "should have a valid factory" do
    FactoryGirl.create(:profile).should be_valid
  end
end

describe "address"
  it "should have a valid factory" do
    FactoryGirl.create(:address).should be_valid
  end
end

What is the secret sauce? I've looked on Factory Girl's wiki and all over the web, but I fear I'm not using the right terms in my search. Also, there appears to be 4 different ways to do everything in FactoryGirl with mixed syntax in each search result I stumbled on.

Thanks in advance for any insight...

Update: 12/26/2012

I had the Profile / User associations backwards. Rather than having the User reference the Profile factory, I flipped it around to have the Profile reference the User factory.

Here is the final factory implementation:

User Factory

FactoryGirl.define do
  sequence(:email) {|n| "person-#{n}@example.com"}
  factory :user do
    #profile <== REMOVED THIS!
    name 'Test User'
    email 
    password 'please'
    password_confirmation 'please'
    # required if the Devise Confirmable module is used
    confirmed_at Time.now
  end
end

Profile Factory

FactoryGirl.define do
  factory :profile do
    user # <== ADDED THIS!
    company_name "My Company"
    first_name "First"
    last_name "Last"
  end
end

Address Factory

FactoryGirl.define do
  factory :address do
    user
    association :addressable, factory: :profile
    address "123 Anywhere"
    city "Cooltown"
    state "CO"
    zip "90210"
    phone "(123) 555-1234"
    url "http://mysite.com"
    longitude 1.2
    latitude 9.99
  end
end

All tests pass!

Proficiency answered 21/12, 2012 at 23:11 Comment(4)
What's the single line profile in your User factory for? I assume you are trying to link it to the created FactoryGirl profile?Threaten
You are correct. I'm trying to create a user with a prebuilt Profile. The reason is that in my after_initialize method on User i build a profile, but when I save it the validation doesn't allow User to save due to blank Profile values...?Proficiency
@jason328 you should post your answer and I'll give you credit. Your comment was the fix! :) Thanks a bunch!Proficiency
@luc Could you please post the final (fixed) User model for clarity's sake?Sinless
T
2

As per questioner's request,

You left profile blank. In order for User and Profile to be linked, you need to fill the rest of the line out and let FactoryGirl know that User and Profile are linked.

Threaten answered 22/12, 2012 at 6:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.