Relational DB’s in Ruby

Part II

In the last post we designed an ERD chart to aid in conceptualizing our video streaming application’s schema. Now that we have a better idea of how each of the models will be utilized within the application, we can begin to discuss how we will be establishing the relationships between the tables.

The ‘belongs to’ Relationship

In the previous post we briefly touched upon the has many, belongs to relationship(s). Let’s look back at Wayne’s World to craft an example and shed some more light on this has many, belongs to relationship.

“It’s like people only do things because they get paid, and that’s just really sad.”

Let’s say we had two classes, Person and Car, that represented characters and props from the movie. The character Garth would be an instance of the Person class, and would most likely be initialized with, at the very least, a name and more than likely a few other traits, such as hair color and hobbies. As for the Car class, it would likely have a make, model, year, color, and anything else you might need to know about the car.

Without even thinking of this from a technical perspective, can you see how this relationship between a Person and a Car can be established? People tend to belong to their cars, right? I don’t know about you but I’ve actually never heard of that happening. However, I have heard of cars belonging to people. Some people I know even have many cars that belong to them. So going back to thinking about this technically, how do we establish this relationship?

A class object that belongs to another class object is established via a one-to-one relationship. In this example we have Garth, an instance of a Person, and for our car we will have…

Ah… The Mirthmobile

So we have our Person (Garth) and our Car (The Mirthmobile), and we have already established that a Car will belong to a Person. Let’s start by defining an instance of both our Person and our Car. Using Rails we could create the two with something that resembles the following:

garth = Person.create(
name:"Garth Algar",
next_attr:next_val,
etc...
)
mirthmobile = Car.create(
make: some_make,
model: some_model,
year: some_year,
etc...
)

In its current state, there is now way for the Car to know which Person owns it, and there is no way for the Person to know which cars belong to them. So I’ll ask once again, how do we establish this relationship?

Foreign Keys

We need a foreign key, which is an attribute on one table that is used to identify a row from another table. In our has many, belongs to relationship, we are going to use the Person id as a foreign key on the Car table. Let’s redefine our Person and Car below, taking care to include the person_id foreign key on the car:

garth = Person.create(
name:"Garth Algar",
next_attr:next_val,
etc...
)
mirthmobile = Car.create(
person_id: garth.id,
make: some_make,
model: some_model,
year: some_year,
etc...
)

*Remember, Rails will automatically assign an id attribute whenever it persists a new instance of a class to the database, so there is no need to initialize garth with an id. The following post will cover Rails and how it creates class objects and aids in making these associations in more detail.

Now, when it comes time to find the owner of mirthmobile, we need only to use garth’s id and compare that with the person_id of the Car:

Person.all.select { |person| person.id == mirthmobile.owner_id }

So why does our Person not have an attribute for their car? Since a Person can have many cars, it is bad practice to keep each Car instance on our Person table since a Person could (theoretically) have an infinite number of Car objects. Sure, a great deal of car owners only own 1 or maybe 2 cars, but there are some people out there, like Jay Leno, who own over 150 cars (Jay Leno supposedly owns 169 cars, in addition to 117 motorcycles).

Sick whip, bro

Although these tables enable us to make advanced queries in regards to our database, we want the tables to be simple — less is more in this instance, so let’s keep our tables as concise as possible.

Belongs to in Our Video Streaming Application

By looking back to our ERD, we can see a variety of belongs_to relationships in our schema:

The has_many, belongs to relationship comprises most of the models in our application. They are as follows:

  • Videos belong to Content Providers; Content Providers can have many Videos
  • Videos and Subscribers can have many Streams; Streams can have many Videos and many Subscribers
  • Credit Cards and Invoices both belong to Subscribers; Subscribers can have many Invoices and/or Credit Cards
  • A Subscriber can have many Subscriptions; Subscriptions can have many Subscribers
  • Subscriptions have a Subscription Tier; Subscription Tiers can have many Subscriptions

Here’s another has many, belongs to example, using Content Providers and Videos from our streaming app:

paramount = ContentProvider.create(
name: "Paramount",
concurrent_stream_limit: 550
)
=> #<ContentProvider id: 2, concurrent_stream_limit: 550, name: "Paramount", created_at: "2017-10-08 03:29:46", updated_at: "2017-10-08 03:29:46">
waynes_world = Video.create(
title: "Wayne's World",
length: 94,
content_provider_id: paramount.id
)
=> #<Video id: 6, title: "Wayne's World", length: 94, content_provider_id: 2, created_at: "2017-10-12 05:34:46", updated_at: "2017-10-12 05:34:46">

Our Content Providers class is pretty simple, and saves only a name and a number that represents the amount of concurrent streams a video they provide can have. The Video class is pretty simple as well, but it does rely on a bit of information from our Content Provider’s table.

Notice the content_provider_id in the Video’s create method? You’ll see that it is using the id attribute from the paramount Content Provider object. This is what enables us to establish the belongs to, has many relationship between to our two classes. Now, with the help of some Rails magic (which we will discuss in a later post), we can view a list of each Video that belongs to a ContentProvider using basic Ruby syntax:

paramount.videos
=> #<ActiveRecord::Associations::CollectionProxy [#<Video id: 3, title: "Mrs. Doubtfire", length: 118, content_provider_id: 2, created_at: "2017-10-08 03:29:48", updated_at: "2017-10-08 03:29:48">, #<Video id: 4, title: "The Land Before Time", length: 118, content_provider_id: 2, created_at: "2017-10-08 03:30:09", updated_at: "2017-10-08 03:30:09">, #<Video id: 6, title: "Wayne's World", length: 94, content_provider_id: 2, created_at: "2017-10-12 05:34:46", updated_at: "2017-10-12 05:34:46">]>

Conclusion

We went pretty deep into the has many part of the has many, belongs to relationship. In our next post, we are going to look at belongs to side of this relationship, as well as begin to cover how we can use Rails to aid in creating our database and schema.