Ruby Belongs-to/Has-Many Relationships
After reading this article you should walk away with a better understanding of how to express relationships in Ruby, without the use of ActiveRecord. For those who don’t know, Active Record is a Ruby Gem - a convenient tool that allows us to build associations using SQL and databases. Now before moving forward, I will be mentioning some concepts worth noting and refer to them throughout the article so they are defined within the context that I will be using them.
Before writing out code, it’s important that we write out what models we will be using. Let’s use the Avengers — or any group of superheroes, as an example to demonstrate “Belongs-to” and “Has-many” relationships.
Here are our Models:
1. Team (Avengers)
2. Hero (Hulk/member of Team)
Let’s just play with these two models for now. Here is what we want to create.
Avengers <Has Many> Heroes
Heroes <Belong_to> Avengers
Now let’s create our basic code and build from there:
Here we have our class Team. Where a team gets initialized with a name(ie. “Avengers”) and year (ie. 1999).
It has a class variable @@all which starts as an empty array ().
When a Team is initialized, that team gets pushed into the @@all array(). And lastly, we create a class method (self.all) that when called on, returns an array () of all Team instances.
Here we have our class Hero. A new Hero gets initialized with a team (avengers), a name (“Hulk”), and signature (something the hero is known for: ie.“Big and Green”).
Hero, has a class variable, @@all with the value of an empty array ()as well. Upon initialize, it will shovel each instance of a hero into its array.
Again we created a class method (self.all) which returns an array() of all Hero instances.
Now let's create some seed data, or sample code so we don’t have to constantly initialize new instances of Hero or Team in our terminal:
For the class Team, we created a variable (avengers) with the value of a name and year. And we have four instances of Hero with their associated team (avengers), a name (“Thor”), and a signature (“Big Hammer”).
This Team has many heroes, but how do we connect or Associate the two?
First, we have already associated the two classes. By creating an instance variable, “team” inside of our Hero class. That Team is associated & “Belongs-to” each specified Hero.
Second, we will need to build a class method inside our class Team so that the Team has a list of its many heroes. Here is what this looks like:
1. A method called “heroes” that goes into the Hero class,
2. Calls on the “Hero.all” (or self.all) method which:
a) uses the “select” enumerable to pinpoint each Hero instance that has the “team” value (i.e. self which in this case is avengers) and
b) outputs a large array of each of the Hero/Team values.
The following class method, “hero_names”:
1. Calls on the previously defined “heroes” method and then
2. Maps (or collects) the name value of each of the heroes associated with the Team(avengers).
And there we have it! Inside of our class Team, we used a method that collected each Hero name instance, which in our avenger's example outputs:
=> [“Captain America”, “Iron Man”, “Hulk”, “Thor”]
You can now further play with this code, creating more Team and Hero instances. But wait! What if we want our current hero to be a part of many teams?
Enter the “Many to Many” relationship. Also known as the “Has Many Through” relationship.
To move forward, let’s first look at our new model
First in order to build this relationship we need to in fact create one more model or class and refactor some of our data, which I will share with you in a future article.