Peter Evjan
Peter Evjan

Reputation: 2433

How do I set up my fixtures for a has_and_belongs_to_many relation?

I have the following models:

class Company < ActiveRecord::Base
  has_and_belongs_to_many :regions

class Region < ActiveRecord::Base
  has_many :requests
  has_and_belongs_to_many :companies

class RequestForProposals < ActiveRecord::Base
  belongs_to :region

Whenever I get a new request, I want to send a notification to the companies active in the same region.

How do I set this up in my fixtures so that I can unit test the logic of finding the right companies?

I've tried

region_ids: 1, 2
regions: one, two

in companies.yml, but neither works in assigning regions to the companies.

Here is a gist of the SQL generated: https://gist.github.com/2713518

Upvotes: 26

Views: 7659

Answers (4)

gertas
gertas

Reputation: 17145

In addition to accepted answer if you have a need to calculate such id by yourself, e.g. you have some loose references or another datasource just add:

def fixh(key)
  ActiveRecord::FixtureSet.identify key
end

to your test_helper.rb and then use this way in fixtures:

security_context1:
  ext_id: <%= fixh :user1 %>

Upvotes: 0

oldhomemovie
oldhomemovie

Reputation: 15129

I'm unsure how does one use YAML fixtures these days. Have you tried FactoryGirl for creating db object instances while testing? It does pretty much the same as fixtures, in a much sophisticated way though.

The following passages assumes you are using rspec as a testing framework.

After including factory_girl-rails in your Gemfile and updating spec/spec_helper.rb accordingly to the factory_girls README, create the following files:

# spec/factories/company_factories.rb
FactoryGirl.define do
  factory :company do
    title { |n| "Test Company #{n}" }

    # whatever else fields

    after_create { |company| company.regions << FactoryGirl.create(:region) }
  end
end

# spec/factories/region_factories.rb
FactoryGirl.define do
  factory :region do
    # whatever fields here
  end
end

# spec/factories/request_factories.rb
FactoryGirl.define do
  factory :request do        
    # whatever fields here
  end
end

Now the real question is - what's the actual test code you're doing?

Upvotes: -1

Frederick Cheung
Frederick Cheung

Reputation: 84182

For

regions: one, two

in companies.yml to work you need to let rails auto assign the ids for the regions. This is because (in order to avoid having to have read regions.yml before companies.yml) rails calculates the ids it sticks in the join table from the names of the companies fixtures. if you've assigned the ids yourself, they won't match up with the calculated ones.

From the sql you've provided it looks like you're setting the ids on the regions to 1 and 2, i.e. your regions.yml has

one:
  id: 1
  name: MyString 

Remove the id:1 and you should be ok. You'll also need to update any other files (e.g. request_for_proposals.yml) that refer to regions, replacing

region_id: 1

with

region: one

Rails will know that means to set region_id to the id for the region with label one in your fixtures.

Upvotes: 41

Salil
Salil

Reputation: 9722

Is your regions.yml in test/fixtures directory? How about companies.yml? Your code "regions: one, two", for a given company, should work.
Rails automatically loads the fixtures in this directory when you run the test. If the locations are correct, please post the test output - sql generated - when you run the tests.

Upvotes: 0

Related Questions