Polymorphic associations can be tricky to understand and many times one can get confused about when to use them, how to use them and how they are different from other associations. In this article we will go over these issues.
Active Record Associations are one of the most important features of Rails. Polymorphic association is part of these associations. Ruby on Rails Guide states “with polymorphic associations, a model can belong to more than one other model, on a single association”.
While writing some rails application you will run into situations when you have model associations that seem to be similar, for example lets assume you have Course and Lab models in your application. Now each of the Course and Lab need Teaching Assistants, so you need associate Course and Labs to their corresponding TAs. If you use
has_many/belongs_to kind of association here, you will have two similar models for TAs of course and TAs of Lab. Instead of having two different models you can have a single model i.e TeachingAssistant and you can associate this model with Course and Lab models using polymorphic association.
Lets see how to implement it. First we will need to create TeachingAssistant model.
ta_duty_id is a foreign key and
ta_duty_type will tell model
TeachingAssistant which model it is associated with.
1 2 3 4 5 6 7 8 9 10 11
Now our model is generated, to run the migration do
rake db:migrate. Now lets set up polymorphic association model
1 2 3
By making Teaching Assistant
ta_duty instead of any other model we have declared polymorphic association. Note that we do not have any
ta_duty model/class in our application,
ta_duty is just taking care of polymorphic association. Now lets look at other side.
1 2 3
1 2 3
Code above says that Course and Lab has many TAs via polymorphic association ta_duty. Lets take a look a pictorial representation of polymorphic association we are setting up. We can see how model
TeachingAssistant is associated with two model
Lab in single association via
ta_duty which is helping in achieving the association.
Now lets test this in rails console. Type
rails c and follow the commands.
1 2 3 4 5 6 7 8
We added TeachingAssistant details, created Course and created association between Course and TeachingAssistant via polymorphic association
ta_duty. In line six we tested if the association works.
STI vs Polymorphic Association
Single Table Inheritance(STI) is often compared with polymorphic associations. It can a good alternative to polymorphic associations(depending upon the situation). In STI you inherit similar models from base model which inherits from
ActiveRecord::Base, so in our case
1 2 3
From following figure you will get clear picture how single table inheritance is different from polymorphic association and see how STI looks like.
As we can see STI provides you with more flexibility than polymorphic association but we have to create separate classes to implement the associations. STI adds lot more code and can be difficult to implement compared to polymorphic association. Although you should take final decision depending on use case. In our case polymorphic association is clearly a better choice than STI.
Combining has_many :through and polymorphic association
There can be special cases where you need has_many :through with polymorphic association. Although not difficult to understand/implement, one might get confused the first time. So lets say Professor wants to know what courses/labs were assigned to his phd students/TAs. This can be made possible by doing the following.
1 2 3 4 5
1 2 3 4
That’s it, we have combined
has_many :through and polymorphic association. To test you can make queries like
Professor.first.course_tas. Note that we have added association between Professor and TAs, so make sure you make corresponding changes.
When adding Bi-directional Associations in rails application, one uses
inverse_of: option provided by Active Record.
inverse_of: does not work with polymorphic associations.
We covered basics & implementation of polymorphic associations in rails, compared it with other associations and saw how it can be extended with other associations. Once you understand correct and appropriate use of polymorphic association you can make your rails application more efficient.