Ruby Object Oriented Programming: Single Source of Truth
By: Sam Passarelli
Tags: Flatiron School, Object Oriented, Ruby

PHEW! Now that I don’t have to explain Ruby OOP basics, let’s go ahead and begin talking about how associated classes can “store” and retrieve class instances from another class.

Associations and Relationships

When creating classes in Ruby, you have to consider whether or not these classes have any relation to one another. Let’s say, for example, in the same program, you create a “Headphones” class and a “Chair” class (that does chair things ¯\_(ツ)_/¯). You would have to ask yourself, “Do either of these classes have any type of relationship or association with one another?”. In this example, I would bet that these have very little association.

BUT, what if we had a classes in the same program like “Uber Driver” and “Passenger” or “Artist” and “Song”? We now have a situation where one class has a relationship with another class. To make a relationship easy to understand, it is helpful to physically draw out the type of relationship. There are 2 types of relationships this article will cover: “One to Many” and “Many to Many”.

One To Many

This type of relationship is created when there is ONE class that “belongs to” another class. In our example from above, the Artist and Song classes will have this type of relationship (at its most basic level). Like I mentioned above, to see the relationship, it is very helpful to draw it out.

“Many” is illustrated by having the forks at the end of the relationship line.

In this case, one Artist has many Songs but a Song belongs to one Artist. So which class is going to house the information about the other class and become the Single Source of Truth (SSOT)? The answer is the BELONGS TO class. In this case, it is the Song class.

But how does the Song class “store” the Artist’s information? When an Artist instance gets initialized, it takes in just one argument, “name”. When a Song instance is initialized, it takes in arguments of “title”, “album”, “genre”, and “artist_instance”.

The item linking the two classes is the“artist_instance” argument for the Song class initialization.

Lets look at some examples of newly created Artist and Song instances:

As you can see, the Artist INSTANCE of “ariana” is being passed as an argument into the creation of a Song instance. The rest of the song arguments are plain old strings.

This allows us to create methods inside the Artist class to pull information from the Song class since that is the Single Source of Truth (SSOT). Take the below example: The #all_songs instance method on the Artist class is going back to the Song class and iterating through the songs and pulling out all songs related to the Artist instance being called.

For the #all_songs method, if the Artist instance of “drake” was called (drake.all_songs), it would return the Song instance of “headlines”. You are able to dive deeper and pull out just the song’s “title” by mapping over the instance.

Making any sense yet? 😬

Many to Many

We will use our earlier example of “Uber Driver” and “Passenger” as a Many to Many relationship. An Uber Driver can have many passengers throughout their day and a Passenger can have many Uber Drivers during their day as well. What is the thing that brings these two people together?…a Ride. A Driver has many passengers through rides and a passenger has many drivers through rides.

In this program, the Ride class will be the “joining class” that will link the Driver and Passenger class. Think for a second and try and recall how we linked the Artist and Song classes. We used an Artist instance as an argument when creating a new Song instance.

In the case of the Ride class, it will need both a Driver and Passenger instance passed through as an argument when being created (as well as distance for this example).

Because the Ride class belongs to the Driver and Passenger and takes in the driver and passenger instance, this class will become the Single Source of Truth (SSOT). This will allow us to access data across classes by accessing the Ride class.

So let’s say we have some newly initialized Driver, Passenger, and Ride instances. You can see that the driver and passenger instances are being used as arguments in the Ride instance and the distance is a plain integer.

The three classes will look something like the below image. The joining class, Ride, will house the related instances and be the SSOT for calling methods to find driver or passenger data from other classes.