Modelling and Programming M:N relationships — Ruby

Tjbachorz
4 min readSep 8, 2020

--

The basis of Object-Oriented Programming (OOP)

What is the “Single Source of Truth”?

When I first started learning about Object-Oriented Programming (OOP), I struggled with the idea of a “single source of truth”. Simply put: “Where’s my one-stop-shop to get all the information I need in regards to modelling a relationship with code?” When dealing with many-to-many (M:N) relationships, that answer can seem elusive, but it doesn’t have to be.

Let’s get meta here and think about the relationship between bloggers, and readers.

Setting up our classes…

The setup for our Blogger class
The blueprint for a “Blogger” class instance in Ruby.

Here, we have our Blogger class initialised with two attributes: Name and Genre. The “attr_reader” means that once our blogger instance is created, their name information will be readable, but not writable, meaning it won’t be able to change, whereas the genre is an “attr_accessor” meaning that it can both be read, as well as overwritten — we don’t want to pigeonhole our bloggers after all.

Now, let’s make another class for reader…

The blueprint for a “Reader” class instance in Ruby.

Our Readers will be initialised similar to our Bloggers — just a name attribute that cannot be overwritten.

Now how do we connect these two? A reader can follow many different bloggers, and a single blogger can have multitudes readers. How do we marry the two together. What we need a bridge in the form of a third unique class. Readers subscribe, or follow different bloggers, so let’s call it a “Subscription”!

Our Subscription blueprint that marries bloggers and readers..

Our subscription class takes a blogger object, and a reader object and creates a class instance of a subscription. Now that we have all of our blueprints, let’s go ahead and make some class instances!

Using our class blueprints to create class instances of bloggers, readers, and subscriptions to marry the two.

This is a powerful connection that gives us a single source of truth!

Why is a single source of truth important? Well, now all of our information can be found in one place — Subscriptions! Don’t believe me? Let’s find the names of all the readers for “blogger1”, so that when you call blogger1.readers, the list of names will be returned.

Our method to return all of the readers for a given blogger class instance. This method will be found in the same file as our Blogger class blueprint, but it’s calling methods on our Subscription class model.

Remember, this is a method called on a class instance of blogger, so the blogger instance, self, is always present.

First we “select” all of the subscriptions to that blogger class instance (self), then we “map” through them twice — once to get all the Reader class objects associated with those subscriptions, and then once again to get a list of names of those readers. Remember, we made our :name attribute readable for our Reader models, so why not call on it!

All of the readers subscribed to “blogger1”.

We can now make similar methods, all using our “Subscription” class model. With out single source of truth, we can find any information we want relating to bloggers or readers. We can find all the bloggers a particular reader subscribes to — or find all the readers subscribed to a blogger that have notifications turned on — or all the “tech” bloggers a particular reader subscribes to.

In OOP, drawing relationships with a strong single source of truth allows programmers easy, accessible paths to the information they want, freeing their mental bandwidth to tackle more difficult programatic issues.

--

--