Rails: A Self-Referential Association Example
As one delves deeper into Ruby’s Object Relational Mapping, one inevitable stumbles upon a relationship type, named Self-Referential Relationships. While I was searching for a guide to better my understanding of this sort of association, I’ve found many articles quite confusing, so I will attempt to make an easier to follow example.
Whilst many relationships form join tables to connect two instances of two different classes (such as: drinks class, and ingredients class), a self-referential relationship invokes a join table that connects two instances of the SAME class.
This type of Association is rather frequently used. Let’s say you’re modeling Instagram follows. There is a user that follows another user, establishing the USER as the follower, and another USER being followed, the followee.
Another example, somewhat more practical is that of a Drag Race.
A drag race consists of two cars, so let’s create a car model. To keep track of each instance of a race, we’ll create a DragRace class, which holds a first_car, and a second_car.
Then, we have to establish the relationships. Remember that each instance of DragRace belongs to two CAR classes, so we have to specify that the class name is Car.
Thanks to this declaration, when we create DragRace(s) in our seed file, we can specify that DragRace.create(first_car: ____, second_car: ______), and ruby will know both are Car objects.
Writing out the associations for the Car model is the tricky part. However, I’ll try to make it as concise as possible.
I’ve named two has_many to the join table as :temp and :temp2 to show that these are merely bridges to the end results, which is :second_cars, and :first_cars. So let’s go through the code above.
The Car model has many drag races, and that Car itself will either be car1 or car2. If that car is first_car, it has many second_car opponents through temp. Else if that car is second_car, that car has many first_car opponents through temp2. Temp and Temp2, however, are the same join table. The source just points to the row of the join table that the data is coming from. If one has_many :second_cars, then that :second_cars is coming from the second_car field on the join model.
That’s it! Now we are able to create Car models, and also DragRace join instances!