Skip to content

Instantly share code, notes, and snippets.

@betweenparentheses
Last active August 29, 2015 14:16
Show Gist options
  • Save betweenparentheses/0b6b325ceaaea76a521d to your computer and use it in GitHub Desktop.
Save betweenparentheses/0b6b325ceaaea76a521d to your computer and use it in GitHub Desktop.
Seeding the Viking Store Solution Notes

Seeding the Viking Store

By now, you've spent hours and hours on SQL alone, then more hours learning how to translate it back into ActiveRecord. Hopefully, data models are starting to make more sense for you at this point.

As for this assignment, there were two equally weighty parts to the assignment: setting up the data models in the first place, then seeding them up with useful fake data. This solution will walk through each one separately.

##Data Model Planning

You've already had experience planning out the model for a store, so this part of the assignment should have been relatively familiar. Even so, it was more complex than the earlier examples.

In addition to the basics -- A User has-many Addresses, a Product is in a many-to-many relationship with an Order (see the Amazon.com example from earlier) -- there is at least one gotcha:

####Default Shipping and Billing Addresses What kind of relationships are these? Remember, each and every relationship is independent from every other relationship. This kind of relationship is not the same as the basic User-has-many-Addresses relationship, even if the data models involved are the same. Instead, think about how a User has one default billing address, and has one default shipping address.

Each one is going to involve its own foreign key, which should live on the User model. Why? Because a User who has just created an account might not have a billing address set up, but there is never going to be a default billing address relationship that didn't have a User around to point to it.

###One Catch With Orders-- Shopping Carts Shopping Carts are weird. The way the problem is set up, a shopping cart BECOMES an order when you check out. Since it is exactly the same as an Order except that it doesn't have a checkout_date, why not simply add in a flag to check whether an order has been placed? This may not be perfectly normalized, but it does DRY out your code for handling orders and shopping carts. The only difference: you are going to have to take care in your seeds.rb to generate only one shopping cart. If a User already has a shopping cart, all the rest of their orders should have a checkout date, to avoid confusion.

###Don't Forget Your Join Tables

When you got to the prospect of an Order having many Products in it, but the same Product showing up in multiple Orders, hopefully you realized, Many to Many! Since only this OrderContents join table actually knows both who did the ordering and what they ordered, it's also the only place you can store how many of Widget X were ordered by User 493 as part of their order on July 20.

###Relationships Make Deletion Hard Think about it: if a User deletes an address, what happens to previous Orders that were sent to that address? Should they point to NULL and throw errors in your application, or should that information somehow be stored? For almost any application you can think of, it is much more robust to soft-delete objects by giving them a DELETED column. Any object where that field is true should simply not be displayed except in the rare cases where you need them. This demo does not actually implement this pattern, but soft deletion is a very common practice worth knowing so you don't turn your database relations into swiss cheese.

##Seeding is Simpler Than You Think

The hardest part about seeding is that there are so many steps. The easiest part is that every single step is something you could have walked through in Rails Console first. seeds.rb is just a Ruby script of things you could have done in Rails Console if you wanted, triggered by the command rake db:seed. (As a matter of fact, keeping Rails Console open for exploratory coding is a really good idea while writing this thing.)

###Build Independent Objects Before Dependent Objects The complicated thing about seeding this database is just making sure you build the right model objects in the right order. For example, if an address is going to have a user_id as part of a has-many relationship, you need to build the users first so you can access those IDs. If you did things in the wrong order, you probably found yourself circling back and adding new IDs to objects later on, which gets very confusing.

###Finally:

The steps of this seeds file roughly look like:

  • destroy everything in your database that already exists, so you don't need to run rake db:reset every time
  • set a MULTIPLIER constant that scales up all your creation loops further on in the app
  • create Cities, States, and Categories (for products), since Products and Addresses depend on them
  • Create Products that point to the Categories you just made
  • set up methods to generate Addresses linked to those Cities and States
  • create Users in a two-part process
    • create a User with as many Faker gem-filled fields as possible
    • as soon as the User is saved, create a bunch of Addresses with a foreign key of that User's id
    • THEN, out of those new Addresses, pick one or two to become the User's shipping_id and billing_id. Save the User again.
  • Finally, create Orders based on a User and one of their Addresses by ID
    • remember not to create more than one shopping cart
    • for each Order, pick some products at random, fill in random quantities, and create a few OrderContents

NOTE: This solution repo is copyrighted material for your private use only and not to be shared outside of Viking Code School.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment