views:

386

answers:

3

I'm trying to use fixtures to add more complex test data in order to test specific scenarios with the front-end, which is in Flex. I'm not sure this is the right way to go about it with rails. My rails app is a card game and the 'more complex test data' I'm trying to test are various combinations of cards.

For example, I want to set up a test game where player 1 has cards B and C in hand, where I've specifically added cards B and C to the player's hand in a fixture.

I have basic fixtures for players, games, and users, which have been there for awhile and working fine. I've tried to add the following erb code in the games fixture, to invoke the Game.start method, and am getting

NoMethodError: undefined method `games' for main:Object

The fixture code snippet is :

four:
  id: 4
  num_players: 3
  turn_num: 0
  status_id: 1

<% game_four = games(:four).find
   game_four.start
%>
+5  A: 
game_four = games(:four).find

games method exists only in test cases, not in fixtures. You should either query the database or use relationships. This is just an example.

four:
  id: 4
  num_players: 3
  turn_num: 0
  status_id: 1

<% Game.find_by_name(four).start %>

Also, this is not really the right place for such command. Fixtures are not intended "to start games". You should really move this command elsewhere, perhaps in a dedicated test case within the setup block.

EDIT:

I copy here my comment posted a couple of days ago on the original answer with a link to the new Rails Database Seeding feature: http://ryandaigle.com/articles/2009/5/13/what-s-new-in-edge-rails-database-seeding

This is the one explained by Yehuda Katz in his answer and definitely the best way to solve this problem.

Simone Carletti
I tried the find_by_name, but I don't have a 'name' attribute so instead I tried doing <% Game.find(4).start %> and it says it can't find a Game with ID=4
find_by_name was just an example. You should use a proper identifier for the game. You can't use the ID because they are uniquely generated by Rails and they don't reflect the item number in the collection as you might expect.
Simone Carletti
+4  A: 

Probably the best solution (and in fact, the one that is now canonized on edge) is to have a seeds.rb file in your db directory that you load from a rake task.

Here's what Rails does now on edge (to be in Rails 3).

# db/seeds.rb
# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
#
# Examples:
#   
#   cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }])
#   Major.create(:name => 'Daley', :city => cities.first)

And then a new rake task (which you can add to your Rakefile):

desc 'Load the seed data from db/seeds.rb'
task :seed => :environment do
  seed_file = File.join(Rails.root, 'db', 'seeds.rb')
  load(seed_file) if File.exist?(seed_file)
end

If you set up your seeds.rb file this way, you will be following the new convention and will be able to delete the seeds rake task when you upgrade to Rails 3.

Also, migrations are not for data. This is well established and the universal opinion of the Rails core team as far as I know.

Yehuda Katz
Thanks much for your post; I gave the answer to weppos because it answered the specific question in the post; however your answer is extremely helpful for the larger picture of what I'm trying to do, and how to do it in the current Rails conventions
A: 

If you want to use fixtures method (when loading data for development, not during tests) you can use fixtures_references plugin. Its behaviour will be the same.