AR Association Explorations

Creating ActiveRecord associations are by far one of the most powerful techniques to master when doing rails. And playing with these associations is sort of like an art. Because there are a finite number of associations that you can make in Rails. But you can make connections with them in sooo many interesting ways. As you all know, these associations are made available through the ActiveRecord association methods DSL: has_many, has_one, belongs_to, etc.. These association methods are powerful and if utilized correctly can do wonders for putting rails models together to build interestingly connected business objects.

In this post I will be picking out some associations that I’ve come across out there in the wild(github). The idea is to go over, via repetition how a person would go about reading custom rails associations and therefore informing the creation of custom rails associations. All the while practicing my own rails decoding skills.

The first app that I came across and happened to like can be found here: https://github.com/waterflowseast/waterflowseast/blob/master/app

This application waterfloweast is a great specimen of model associations put to great use. There are 12 models in total and all are very carefully connected in a wide variety of interesting ways. Let us look over these interesting connnections.

First up, there is a model called connecting_relationship.

1
2
3
4
class CollectingRelationship < ActiveRecord::Base
 belongs_to :post
 belongs_to :user
end

This model is a fairly empty model. However this model is interesting for 2 reasons. For 1, its name is connecting_relationships. For 2 it has exactly 2 belongs to associations with single noun models. Whenever you come across models like this, if you look in the schema you will find most times that this is in fact a join model - they store 2 foreign keys. Meaning that this models purpose is to connect two other models together with their foreign keys stored in its table.

Join Models are used when you want to relate 2 objects in a Many to Many association. Many to Many can be realized more easily by telling yourself many things can belong to many other things. I personally didnt understand this for a while, but after 2 years of doing rails, somehow the language starts to make sense.

If we go to the Users model and to the Post model respectively, we can verify this statement. In the Users Model we see:

1
2
3
4
5
6
class User < ActiveRecord::Base
 ...
 has_many :collecting_relationships, dependent: :destroy
 has_many :collections, through: :collecting_relationships, source: :post
 ...
end

in the Post Model we see:

1
2
3
4
5
6
class Post < ActiveRecord::Base
...
 has_many :collecting_relationships, dependent: :destroy
 has_many :collectors, through: :collecting_relationships, source: :user
...
end

In the User Model the bottom association is creating a collection proxy object called collections - (a collection proxy object is pretty much an array. You can test this connection in the console by creating a new User object and then typing u.collections. This will return an empty array type structure.) This means that a User can have many post that will be returned by calling User#collections. Furthermore, These posts are being retrieved through a table called collecting_relationships. And because the name “collections” is pretty much a made up name, the association has the source optionbeing specified. The source: :post specification tells the User model to look for the post_id foreign_key on the collecting_relationships table. And thats pretty much it for the users model. From this, you basically can retrieve many posts as a collections array.

This exact same break down is also true of the Post model. There is a collection proxy object called collectors( a made up name). Then the user records are being retrieved from the collecting_relationships join table by saying through: :collecting_relationships. And then finally the source is being specified by saying source: :user wich notifies the post model to look for the user_id foreign key on the collecting_relationships table. All this gives you the ability to get all the users on a specific post. And pretty much that’s how you read a many to many relationship through a join model.

These next 2 associations I am going to go over are actually the types of associations that I will honestly say, are the kinds of associations that once you start making them, pretty much confirms that you are a pretty good rails developer. These are the types of associations in my opinion that give object interactions some very powerful descriptions. Lets take a look at them.

1
2
3
4
5
6
class Invitation < ActiveRecord::Base

belongs_to :sender, class_name: :User
has_one :receiver, class_name: :User

end

These associations are actually two associations belonging to the same model. This class invitation has a sender that belongs to the user class and it also has one reciever that comes from the user class. The special part about this relationship is that it gives you a very descriptive way to get the sender and reciever from off of the User model. This is what I would like to call a Friendly Association. It uses the class_name method to make the invitation model smart enough to know that its going to be storing a foreign key called user_id for a sender object and that its going to have one reciever object that is going to come from the users table.

When you look at the Users model, you find the other side of the relationship which confirmes exactly whats going on here:

1
2
3
4
5
6
class User < ActiveRecord::Base
...
 has_many :invitations, foreign_key: :sender_id, dependent: :destroy
 belongs_to :invitation
...
end

This association is saying two things. That the User model can have many invitations and that they will be stored with a foreign_key called sender_id on the Invitations table. And the bottom association is saying that this User model belongs to the invitation model. In which case you can expect that the foreign key will be stored on the Users table as invitation_id. The Thing to really note here is one trick that will make your life easy. When you see a has_one or a has_many and there is a foreign_key option being specified on it. This means that this Class will be storing a differently named foreign key than what rails expects on the opposite table. In this case, instead of saving user_id on the opposite table, it will actually be stored as sender_id. This is a very powerful trick to keep in your mind, because this trick will let you create this Friendly Association to describe many other types of interactions. Things like: Buyer - Seller, Sender - Reciever - Sponsor, Sponsee, Worker - Coworker, etc. etc…

There are soo many examples of associations. Maybe, I should start a series that is based on deciphering what associations are giving. My Ethos is that in reading good code, you actually have a good opportunity to sharpen your own code.