While working on my Rails project, I found out about the existence of the self-referential association. It is a powerful tool to know about. It might seem confusing, but by breaking it down, it makes sense. So, let’s start!
Let’s imagine we have a User table where each user can follow other users, and have other users follow him/her as well.
Self-referential association means we create a JOIN MODEL, such as Friendship, for example, which links another model, such as User to itself, so a user can have many friends (which are other users), and a friend can be befriended by a user ( a follower and a followed).
For example, using our models above, a User has many followers (which are other Users), but can also follow other people. The people a User follows are known as followed.
See the example below:
class User < ApplicationRecord
has_many :followers, foreign_key: :follower_id , class_name: "Friendship"
has_many :followed, through: :followers
has_many :followed, foreign_key: :followed_id, class_name: "Friendship"
has_many :followers, through: :followed
Here we have the model User which
has_many relationships with followers and followed. In other words, these Users need to be connected through foreign keys that we obtain from the JOIN MODEL (Friendship — see model below).
class Friendship < ApplicationRecord
belongs_to :follower, class_name: "User"
belongs_to :followed, class_name: "User"
This JOIN MODEL Friendship is necessary for self-referencing the User model, by first stating that the JOIN MODEL belongs_to a follower/followed, and that a follower/followed is a type of User, which is why we specify the
What we basically do is create multiple relationships between two models. Like in the example above — a relationship is created between User and Friendship through the followers/followed.
Sometimes we will find a model that should have a relationship to itself.
The self-join has no join model! However, a foreign key is added to the same model. For example, you may want to keep track of employees in a business , which can be seen as a single database model. Within the business, you want to be able to trace relationships between employees, such as those between managers and subordinates. Each employee can be a manager or a subordinate, but they are both still employees of the business at the end of the day. The example below shows how even though Employees are a single model, we can separate different kinds of employees and establish relationships between them using a self-referencing table.
Employee < ApplicationRecord
has_many :subordinates, class_name: "Employee", foreign_key: "manager_id"
belongs_to :manager, class_name: "Employee"
The example above is saying that an Employee can be a subordinate or a manager. The manager has_many subordinates, but there’s only one manager per subordinate, meaning that a particular subordinate belongs to a particular manager.
A manager (who is also an employee) can have many subordinates (other employees). To group these employees that they belong to a particular manager we foreign_key them to the manager_id.
If there was no foreign key to manager_id, then to find all subordinates of a particular manager we would have to fully go through the table. By keying employees to a manager_id we can quickly query a manager for all their employees.
As a conclusion:
Rails self referential and self joins are unique because they let us accomplish a lot more queries and structure without creating extra unneeded models like in other programming languages. I highly recommend you to learn more about them and to use them when possible.