How to build a has many relationship with Ruby Objects

Building a has many relationship is all about figuring out what object will be responsible for instantiating the object that it’s related to. For example, if we have a relationship between a Chef and their dish, we would need to decide if Chefs come about from dishes or if dishes come about from Chefs.

When thinking about this problem in real life we can say that a new dish can only come about if a Chef cooks it up. This a good indication that new objects of dishes should come about as long as they are created by an object of a Chef. Since a new dish couldn’t exist unless a Chef existed to cook it up.

In this example a Chef is the object that will have many dishes, and a dish is the object will have one Chef. Therefore the Chef object will be instantiating dishes to establish the relationship between itself and the object of a dish.

Below I have coded an example in Ruby to illustrate what this connection could potentially look like. This example contains classes, and some methods used by them as well. If you are not yet comfortable with those topics, please review them and come back to this post when you are ready.

class Chef

attr_accessor :name, :dishes

def initialize(name)
@name = name
@dishes = []
end

def add_dishes(dish_name)
new_dish = Dish.new(dish_name, self)
@dishes << new_dish
new_dish
end
end
class Dish 

attr_accessor :dish_name, :chef

def initialize(dish_name, chef)
@dish_name = dish_name
@chef = chef
end
end

If we take a look at the code above we have two classes, one for Chefs and one for dishes. Although there is quite a bit of code to go through, the connection really happens within the ‘add_dishes’ method in the Chef class.

 def add_dishes(dish_name) 
new_dish = Dish.new(dish_name, self)
@dishes << new_dish
new_dish
end

This method will add new dishes to our Chef object, and create instances of dishes that know the Chef object that they were created from. Lets dissect this method line by line below:

new_dish = Dish.new(dish_name, self)

The line above creates a variable called new_dish that points to a new instance of an object from the dish class. In order to instantiate the new Dish we are passing it the name of the dish, held by the variable ‘dish_name’. Additionally we are also passing it the keyword ‘self’. Since we are calling this method at the instance level, the keyword self here stands for an instance of an object of the Chef class. By passing ‘self’ to the instance of a Dish, we are creating the link between the two objects. In this way, the instance of a Dish object knows the Chef that created it.

@dishes << new_dish

The code above, will then take the newly created instance of a Dish and push it to an instance variable that points to an empty array. This variable is linked to the instance of the object of a Chef, and will store all the dishes that are created by that chef. This step ensures that the Chef is aware of all their dishes.

new_dish

Lastly I return the new instance of a dish with the ‘new_dish’ variable. This is not a necessary line, but it could potentially make the method more useful to return the instance of the new dish added. You could set this to anything else you may need, or just completely omit it.

Keep in mind that this is just an example and there are countless ways of setting up the connection. However ultimately it will come down to instantiating an object within the class of the object that you want to connect to, and making the objects aware of each other. With our example above, we instantiated dishes in our Chef class, and made the dishes aware of the Chef that they were created by. Thereby connecting new dishes, to the Chefs who cooked them. We also pushed all new dishes into an array, so all Chefs would be aware of all the dishes that they have created.

Hope you found this post helpful. If you have any questions please feel free to leave your comments below.

Thanks! Happy coding!