Dr Seedlove or: How I Learned to Stop Worrying and Love seeds.rb

ocole161

ocole161

Posted on February 17, 2023

Dr Seedlove or: How I Learned to Stop Worrying and Love seeds.rb

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,
Enter fullscreen mode Exit fullscreen mode

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,
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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.

💖 💪 🙅 🚩
ocole161
ocole161

Posted on February 17, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Parameters VS Arguments with Ruby
ruby Parameters VS Arguments with Ruby

October 23, 2024

Usage of method reduce in Ruby
ruby Usage of method reduce in Ruby

October 25, 2023

Methods in Ruby
beginners Methods in Ruby

August 21, 2023

Hashes in Ruby
beginners Hashes in Ruby

August 20, 2023