Behold the Mighty Seed!

by on under Rails
5 minute read

In this post, I’ll talk about a feature of Rails that sometimes gets passed over in beginner-level Rails courses because it is not at all necessary for building web applications, but nevertheless can be very useful. This feature is the ability to add seed data to the database. The best way to illustrate this is by example. During my web development training at [theFirehoseProject] (http://thefirehoseproject.com) I built a restaurant review app called [Nomster] (http://nomster-yury-voloshin.herokuapp.com). When the features needed to add restaurants were complete, I added several restaurants to the database by typing in their information to make sure the places are correctly styled. A few more places needed to be typed in in order to test the pagination feature. But then, a typo during a database migration led to my database becoming inaccessible. The problem had to be fixed by dropping the database and creating a new one. While I appreciated the learning experience that this incident brought me, I did not appreciate having to type in the information for all the restaurants one more time. At that moment, my life would’ve been easier if I could just load a file where all the restaurant information has been pre-loaded.

It turns out that such a file does exist. It is the db/seeds.rb file that is automatically generated by Rails. This is the place where we can enter test data to be used by our application. The data needs to be typed in only once and can be loaded into the app as many times as necessary. This can be very useful for those times when the database needs to be re-created. When working on a development team, seed data can help to make sure that all team members work with a consistent set of test data.

When we open seeds.rb for the first time, we see that it comes with pre-filled instructions:

# 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' }])

#   Mayor.create(name: 'Emanuel', city: cities.first)

These instructions are pretty easy to follow. We use the create method to create instances of our model objects as collections of hashes, where the key is the name of our model attribute and the value is the attribute’s value. Another example comes from [My Recipe Box] (https://github.com/yvoloshin/MyRecipeBox), a recipe-sharing app I put together recently. In this app, a recipe has a :name, :ingredients, :instructions, and belongs to :user. I used the code below to create two seed recipes in seeds.rb:

puts "Creating recipes..."

recipes = Recipe.create([
	{
	name: 
		"Oatmeal Banana Pancakes", 
	description: 
		"Easy and delicious!", 
	ingredients:
		"Old fashioned oatmeal (1 cup) 
		3 eggs 
		1 banana 
		Vanilla extract (2 teaspoons) 
		Vegetable oil for frying", 
	instructions: 
		"1. Combine all ingredients in a blender. 
		2. Process until the mixture is smooth. 
		3. Place a thin coat of vegetable oil on the frying pan. 
		4. Pour 1/2 cup of the mixture onto a frying pan and fry 2-3 
		minutes per side, until the pancakes are golden brown.
		(Recipe courtesy of http://brokeandbougie.blogspot.com)", 
	user_id: 1
	},

	{
	name: 
		"Fish in Tomato Sauce", 
	description: 
		"This is a version of my grandmother's Fish in Tomato Sauce", 
	ingredients:
		"1 lb fish filets (Any fish with firm white flesh will do, 
		such as tilapia or cod. Here, I used tilapia.) 
		1/4 cup all-purpose flour 
		1 large carrot 
		1 onion 
		1 red bell pepper 
		1 14 oz can of tomato sauce 
		1/2 teaspoon sugar 
		1/4 teaspoon each of salt and pepper", 
	instructions: 
		"1. Sprinkle fish with salt and pepper 
		2. Pour the flour on a plate and dredge the fish through flour. Set aside. 
		3. Coarsely grate the carrot using either a manual grater or a food processor. 
		4. Finely chop the onion and bell pepper. 
		5. Fry the fish in a skillet until slightly golden-brown, about 3 
		minutes per side. Remove from skillet. 
		6. Saute the onion in the same skillet until it becomes translucent and starts to brown, about 10 minutes. 
		7. Add carrot, bell pepper, tomato sauce, salt, pepper, and sugar. Saute uncovered until carrots and pepper are tender, about 10 minutes. 
		8. Add fish to skillet and mix well with the sauce. 
		9. Cover and cook on low heat for 10 more minutes.", 
	user_id: 1
	}
])

Puts "All done!"

Once the seed.rb is set up, all we need to do is run rake db:seed and the seed data will be added to the database.

An important gotcha is that, when specifying the user (user_id: 1), a user with this id must in fact exist in the database. If there is no such user, then the app won’t know what to do with this information and the data will be rendered incorrectly. Another useful point to know is, what would happen if we run rake db:seed more than once? It turns out that the seed data is appended to the database every time we run the seed command. Seeding does not affect any database contents that were there previously. But, if we do want to erase the database and replace it with seed data, the command to run is rake db:reset.

database seeding
comments powered by Disqus