This blog covers associations within a model useful to modelling relationships such as friends on facebook.
I am working on a similar scenario where I had to design a model where a user is friends with other users(many to many relationship).
The real challenge here is that all the users are going to be stored in the User model. That way we somehow have to decide how to generate the backward relationship i.e. accessing friends of a particular user.
Designing this relationship requires one more model which will be used only to store the relationship of user and its friends.
For accessing friends of a particular user we need to have a foriegn_key(user_id) which will be used to fetch all the users(friends) which are related to a particular user.
Before we tackle what we actually want to do, let’s first dive in model relationships and try to understand how associations work inside of models in rails.
User model where a user belongs to a company.
class User < ActiveRecord::Base belongs_to :company end
If I have describe relationship in above code in one line this is how I would.
Rails internally adds foriegn_key attribute in user table with name
Under the Hood.
- Rails derives the class name
Companyusing :company and some little ruby magic.
- By default the foreign_key is added with the name of Model, in this case it would be
Interestingly we can override above behaviour.
class User < ActiveRecord::Base belongs_to :company, :class_name => 'User', :foreign_key => 'user_id' end
We can specify the
foreign_key here we are doing nothing but overriding rails process where it decides which class to call and which attribute to use as foreign_key.
This way user model will be used rather than company model for this association and foreign_key attribute would be user_id instead of company_id.
Back to our original friends in a social network
Above I mentioned using a second table which will store the relationship between a user and its friends.
This second table should have two columns
friend_id(i’ll come to friend_id after this.)
So, for a particular user with
id = 1 having 2 friend connections we will have 2 records in this new table with attrs.
- NewModel id: 1, friend_id: 2, user_id: 1
- NewModel id: 2, friend_id: 3, user_id: 1
We have another model to keep track of friends of a user lets think of a name(a good one)…:) Since this model is maintaining friendship b/w users
Friendship sounds like a good choice.
Let’s go back to our
User model and see how to relate it to
A user can have many friends. It implies that for a given user friendship model will have many records. So a user has many friendships. We also want to be able to access friends of a user for that we should add a
has_many :friends Here we are using
has_many: through relationship.
class User < ActiveRecord::Base has_many :friendships has_many :friends, :through => :friendships end
Some Key points to note in
has_many :friendshipsis the association which actually tells rails that we are going to have multiple records of
Friendshipmodel for one record of
has_many :friends, :through => :friendshipsthis line actually tells rails that we will be using
.friendsto access all the records that are related to object calling friends.
- Key thing to note here is through relationship tells rails that friendship table will be used to find out friends.
Lets now define Friendship model.
class Friendship < ActiveRecord:Base belongs_to :user <!--# This ads the user_id column as foreign key--> belongs_to :friend, :class_name => "User" <!--# This ads as friend_id as the foriegn key but essentially points to objects of User class--> end
Friendship model has two attributes
friend_id these both are basically same model id’s.
belongs_to :userimplicitly ads foriegn_key as
user_idremember rails uses
:userand does some magic on it.
belongs_to :friendit points to User class and ads foriegn_key as
friend_idsince we did not override its foriengn_key.
.friends on any user object can be used to fetch all the friends of that user.
All set we now have a working model of friends on a social network. Voilla!!!
After this post I can say I have moved closer to understanding association in rails.
This blog post originally appeared on ashish singh’s blog