January 19, 2009 | In: Development, Ruby on Rails
Fixtures and Model Associations in Ruby on Rails
I’m forcing myself to write tests for all my development on the movie site. (We still haven’t chosen a final name for it – lame…) Once of the things I love the most in Rails is Fixtures.
Fixtures allow you to setup your test data in YAML or CSV. That data is then loaded when you run your functional, unit, and integration tests. You can also just load the data outside of any testing effort by running ‘rake db:fixtures:load’. I can’t even tell you how handy that is. I can populate my development site with data and starting banging around on pages that actually work – with real data – in the blink of an eye. Got a bug? Fix it and reload. It’s niiiice.
As I started building my fixtures, I started with the easy models first. Movie is an obvious choice. This is my movies.yml file:
movie1: title: The Dark Knight director: Christopher Nolan release_date: 2008-07-18 description: Batman Gordon and Harvey Dent are forced to deal with the chaos starring: Christian Bale rating: PG-13 product_url: http://www.amazon.com thumbnail_path: /images/movies/thumbs/the-dark-knight.jpg image_path: /images/movies/full_size/the-dark-knight.jpg number_of_reviews: 5 avg_rating: 8.8 featured: 1 permalink: the-dark-knight movie2: title: Tropic Thunder director: Ben Stiller release_date: 2008-08-13 description: Goofy movie with lots of bid-budget actors starring: Ben Stiller, Robert Downey Jr., Jack Black rating: R product_url: http://www.amazon.com thumbnail_path: /images/movies/thumbs/tropic-thunder.jpg image_path: /images/movies/full_size/tropic-thunder.jpg number_of_reviews: 10 avg_rating: 7.5 permalink: tropic-thunder
Now I have two movies that I can load at any time. But wait. My site is also going to have Movie Reviews in it. Each review be associated with one and only one Movie. In my Movie Review model, that relationship is established by the belongs_to :movie statement at the top of the class. I also have a has_many :movie_reviews statement at the top of my Movie class.
MovieReview has a movie_id column that references the Movie it belongs to. But how can I represent that in my movie_reviews.yml file where I’m entering data? I won’t know the movie_id assigned to my new movies, and I don’t want to have to hardcode it into my movie_reviews.yml records anyway. Enter more Rails magical deliciousness.
Because of the relationship setup in the models, Rails let’s you refer to the record names that you’ve specified in order to relate certain data rows across tables. Here’s my movie_reviews.yml file:
review1: title: My great movie review movie: movie1 rating: 7 review: NO SPOILERS. I saw an advanced showing of this 2 nights before it came out. found_useful: 5 review2: title: Tropic Blunder movie: movie2 rating: 5 review: Great Premise! Started out hilarious...funny 1st half...Robert Downey was great! found_useful: 2
Notice I have specified the movie that each relates to by specifying movie: movie1 and movie: movie2 in each record. Those movie names are the same that I specified in movies.yml. When I run rake db:fixtures:load, I see that the movie_id column in the movie_reviews table has been populated with the correct movie_id from the movies table in each of the two rows inserted.
How cool is that??

