Dr Seedlove or: How I Learned to Stop Worrying and Love seeds.rb
ocole161
Posted on February 17, 2023
Phase 3 of our coding course introduced us to backend development using Ruby. I enjoyed working with the more simplified syntax and powerful built in methods as opposed to JavaScript, but one concept we were introduced to didn't immediately click with me, the creation of a seed file. A seed file, for our purposes, was used to create test data for us to use to test our code. Initially when the projects we were working with were so small, creating a seed file seemed to me to be tedious and unnecessary, when it was just as easy to create data manually in the rake console. As we starting working on larger scale projects however, I soon learned the value of not just having a seed file, but having a robust one that provides plenty of well populated data to work with. In this post I will discuss the basics of building a solid Ruby seed file to be used in testing your code.
For example purposes I will use the code my partner and I used for our Ruby project for class -- a webapp that allowed users to view different coffee roasters, the coffees that they made, and for the user to view and leave reviews for each coffee type. We created a simple backend with 3 tables, with the following relationships:
Each roaster has many coffee types, and has many reviews through coffee types.
Each coffee type has many reviews, and belongs to a roaster.
Each review belongs to a coffee type.
Creating test data in rake console
First let's take a look at how we could manually create test data using rake console. We'll start with creating a roaster:
//You can also use rails console here if you are using rails//
$ rake console
irb(main):002:0> Roaster.create(name: "Corvus Coffee Roasters")
//There will be some info here about how the instance was created,//
//then we'll get the details of our created record below//
id: 1,
name: "Corvus Coffee Roasters",
img_url: nil,
website_url: nil,
We can now use Roaster.first or Roaster.find(1) to use this instance to test. Next we can create a coffee type associated with that roaster, using the id we got when we created that roaster:
CoffeeType.create(blend_name: "Morning Blend", roaster_id: 1)
//...//
id: 61,
roaster_id: 1,
blend_name: "Morning Blend",
intensifier: nil,
origin: nil,
notes: nil,
muffin_pairing: nil,
img_url: nil,
After doing the same process to create a review we'd have 3 instances linked to test on, without much effort. Now let's see what the same process would look like inside of a seeds.rb file:
Creating simple test data in seeds.rb
//This code is here to make sure we wipe all our old seed data//
//before we run db:seed, to keep our test data clean.//
CoffeeType.destroy_all
Review.destroy_all
Roaster.destroy_all
r1 = Roaster.create(name: "Corvus Coffee Roasters")
c1 = CoffeeType.create(blend_name: "Morning Blend", roaster_id: r1.id)
Review.create(reviewer_name: "Owen", review_body: "Great!", rating: 4, coffee_type_id: c1.id)
Note that instead of assigning a roaster_id and coffee_type_id of 1 we declared variables for r1 and c1 and then took their id. This is because if db:seed is run again, it will not start at 1 when assigning ids. In this example if we ran db:seed twice all our instances would have an id of 2. Also keep in mind that the variables r1 and c1 will not be created to be used in your rake console to test with, they are only used inside the context of the seeds.rb file.
Now that a seeds.rb has been created (in our db folder) we can use the command rake db:seed (or rails db:seed) to generate our data.
That was a bit more effort than building manually, but the added benefit is huge. For starters we now have data that we won't need to rebuild every time we reopen rake console to test our data. We also now have a way to reset our data to a consistent point if we end up manipulating our data. The benefit of using a seed file becomes even more clear when you need more than just a few instances created to test your code. Below is the final seed file we created for our project, imagine having to manually type this in every time you wanted to generate your test data!
CoffeeType.destroy_all
Review.destroy_all
Roaster.destroy_all
puts "seeding begun"
# Define constants
muffin_types = ["Blueberry", "Chocolate Chip", "Apple Cinnamon", "Banana Nut", "Lemon Poppy Seed", "Carrot Cake", "Cream Cheese", "Bran"]
coffee_images = ["https://images.pexels.com/photos/1695052/pexels-photo-1695052.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2", "https://images.pexels.com/photos/773958/pexels-photo-773958.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2", "https://images.pexels.com/photos/4109743/pexels-photo-4109743.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2", "https://images.pexels.com/photos/4109748/pexels-photo-4109748.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2"]
# Create Roasters
Roaster.create(name: "Corvus Coffee Roasters", img_url: "https://testedcoffee.com/wp-content/uploads/2021/03/corvus-coffee-picture-for-denver-coffee-roasters.jpg", website_url: "https://www.corvuscoffee.com/")
Roaster.create(name: "Kaladi Coffee Roasters", img_url: "https://testedcoffee.com/wp-content/uploads/2021/03/kaladis-coffee-roaster.jpg", website_url: "https://kaladicoffee.com/")
Roaster.create(name: "Huckleberry Coffee Roasters", img_url: "https://s3-media0.fl.yelpcdn.com/bphoto/SUP3uukMOvxSYzbO3ESQkg/o.jpg", website_url: "https://huckleberryroasters.com/")
Roaster.create(name: "MiddleState Coffee Roasters", img_url: "https://testedcoffee.com/wp-content/uploads/2021/03/middlestate-coffe.jpg", website_url: "https://www.middlestatecoffee.com/" )
# Create CoffeeTypes
20.times { CoffeeType.create(
blend_name: Faker::Coffee.blend_name,
roaster_id: Roaster.all.sample.id,
intensifier: Faker::Coffee.intensifier,
origin: Faker::Coffee.origin,
notes: Faker::Coffee.notes,
muffin_pairing: muffin_types.sample,
img_url: coffee_images.sample
) }
# Create Reviews
50.times { Review.create(
reviewer_name: Faker::FunnyName.name,
review_body: Faker::Quotes::Shakespeare.romeo_and_juliet,
rating: [1, 2, 3, 4, 5].sample,
coffee_type_id: CoffeeType.all.sample.id
)}
puts "seeding finished"
Note: if you are unfamiliar with Faker, Faker is a gem that generates fake data.
Now not only do we have a huge amount of test data to work with, but anytime we want to reset it all back to it's original state it's as easy as running rake db:seed.
I hope you've now realized as I have how valuable it is to put in the time upfront to make a robust seeds.rb file to give you lots of good test data to work with.
Posted on February 17, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.