Recipe 7.2. Creating Fixtures for Many-to-Many Associations


Problem

Creating test fixtures for simple tables that don't have any relations to other tables is easy. But you have some Active Record objects with many-to-many associations. How do you populate your test database with data to test these more complex relationships?

Solution

Your database contains assets and tags tables as well as a join table named assets_tags. The following migration sets up these tables:

db/migrate/001_build_db.rb:

class BuildDb < ActiveRecord::Migration   def self.up     create_table :assets do |t|       t.column :name, :string       t.column :description, :text     end     create_table :tags do |t|       t.column :name, :string     end     create_table :assets_tags do |t|       t.column :asset_id, :integer       t.column :tag_id, :integer     end   end   def self.down     drop_table :assets_tags     drop_table :assets     drop_table :tags   end end

The Asset and Tag classes have Active Record many-to-many associations with each other:

app/models/asset.rb:

class Asset < ActiveRecord::Base   has_and_belongs_to_many :tags end

app/models/tag.rb:

class Tag < ActiveRecord::Base   has_and_belongs_to_many :assets  end

To create YAML test fixtures to populate these tables, start by adding two fixtures to tags.yml:

test/fixtures/tags.yml:

travel_tag:   id:       1   name:     Travel office_tag:   id:       2   name:     Office

Likewise, create three asset fixtures:

test/fixtures/assets.yml:

laptop_asset:   id:       1    name:     Laptop Computer desktop_asset:   id:       2    name:     Desktop Computer projector_asset:   id:       3   name:     Projector

Finally, to associate the tags and assets fixtures, we need to populate the join table. Create fixtures for each asset in assets_tags.yml with the id from each table:

test/fixtures/assets_tags.yml:

laptop_for_travel:   asset_id:     1   tag_id:       1 desktop_for_office:   asset_id:     2   tag_id:       2 projector_for_office:   asset_id:     3   tag_id:       2

Discussion

You include one or more fixtures by passing them as a comma-separated list to the fixtures method. By including all three fixture files in your test case class, you'll have access to assets and can access their tags:

test/unit/asset_test.rb:

require File.dirname(__FILE__) + '/../test_helper' class AssetTest < Test::Unit::TestCase   fixtures :assets, :tags, :assets_tags   def test_assets     laptop_tag = assets('laptop_asset').tags[0]     assert_kind_of Tag, laptop_tag     assert_equal tags('travel_tag'), laptop_tag   end end

See Also

  • Section 7.4"

  • Section 7.8"




Rails Cookbook
Rails Cookbook (Cookbooks (OReilly))
ISBN: 0596527314
EAN: 2147483647
Year: 2007
Pages: 250
Authors: Rob Orsini

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net