corodio8
corodio8

Reputation: 21

Associations in Factory Girl 4.0.0

I just opening up Factory_Girl and I'm trying to figure out how to build dependent factories, most of the questions seem outdated due to the new release.

I'm using associations but other than creating the associated object, that object doesn't seem to be associated or related to the main object in anyway

Basically here's what i have

factory :computer do
  serial_no "12345"
end

factory :allocation do
  association :computer_id, factory: :computer
end

allocation belongs_to computer and computer has_many allocations basically an allocation is a record of any time a computer gets moved or whatnot.

I'm not sure what I'm doing wrong but every time I run this, the computer_id of allocation is '1', but the ID of computer is something random (usually a number between 0-20), and then my test fails because it can't find the proper computer object.

Edit: As if it weren't confusing enough, the actual class name is Assignment, i was attempting to simply. Here's the actual code thats involved, the actual code has no issues because computer_id and user_id are passed to the create method as params during creation.

describe "GET index" do
  it "assigns assignments as @assignment" do
    Assignment.any_instance.stubs(:valid?).returns(true)
    assignment = FactoryGirl.create :associated_assignment
    get :index, {}, valid_session
    assigns(:assignments).should eq([assignment])
  end
end

The Factories involved are

factory :user do
  fname "John"
  lname "Smith"
  uname "jsmith"
  position "placeholder"
end

factory :computer do
  asset_tag "12345"
  computer_name "comp1"
  make "dell"
  model "E6400"
  serial_no "abc123"
end

factory :associated_assignment, class: Assignment do
  association :user_id, factory: :user
  association :computer_id, factory: :computer
  assign_date '11-11-2008'
end

And the controller is:

def index
  @assignments = []
  @computers = Computer.all
  Computer.all.each do |asset|
    @assignments <<  Assignment.where(:computer_id => asset.id).order("assign_date ASC").last
  end
  respond_to do |format|
    format.html # index.html.erb
    format.json { render json: @assignments }
    format.xls { send_data @assignments.to_xls }
end

At the moment i am running this alternative test to check my ids:

describe "GET index" do
  it "assigns assignments as @assignment" do
    Assignment.any_instance.stubs(:valid?).returns(true)
    assignment = FactoryGirl.create :associated_assignment
    get :index, {}, valid_session
    assigns(:computers).should eq([assignment])
  end
end

Which returns something to the effect of the following, where the ID of computer is random but computer_id of assignment is always 1.

Failure/Error: assigns(:computers).should eq([assignment])

   expected: [#<Assignment id: 12, user_id: 1, computer_id: 1, assign_date: "2008-11-11", created_at: "2012-09-10 23:59:48", updated_at: "2012-09-10 23:59:48">]
        got: [#<Computer id: 14, serial_no: "abc123", asset_tag: 12345, computer_name: "comp1", make: "dell", model: "E6400", created_at: "2012-09-10 23:59:48", updated_at: "2012-09-10 23:59:48">]

Upvotes: 2

Views: 1113

Answers (2)

Troy
Troy

Reputation: 5399

I think the problem is with :computer_id vs. :computer. Here's one way to do it that uses FactoryGirl's ability to infer factories and associations:

factory :computer do
  serial_no "12345"
end

factory :allocation do
  computer
end

Further, if you want each computer to have a unique serial number in your specs, use:

sequence :serial_no do |n|
  "1234#{n}"
end

factory :computer do
  serial_no
end

factory :allocation do
  computer
end

Factory Girl is aware of your model and its associations, so it can pick them up and infer how to create related objects.

Thus:

allocation = FactoryGirl.create :allocation

creates an Allocation object and an associated Computer with a serial number of 12340. The id of the Computer object will already be in the Allocation's computer_id field so the relation is completely set up. allocation.computer will work, and allocation.computer_id will be the same as allocation.computer.id.

This uses some syntax sugar of FactoryGirl. You can be more explicit by supplying association (field) names and factory names:

factory :computer do
  serial_no "12345"
end

factory :allocation do
  association :computer, factory: :computer
end

Upvotes: 1

Jeremy Aube
Jeremy Aube

Reputation: 616

Factories don't guarantee what ids anything will have. But you can find the proper computer object via:

allocation = FactoryGirl.create(:allocation)
computer = allocation.computer

Upvotes: 2

Related Questions