When setting up an API in Rails it is crucial to establish how all of your models are going to be connected to each other using Active Record Associations. Polymorphic associations are a little more advanced but can be very useful when your application becomes more complex.
This is a new concept for me and so far I have learned that polymorphism is a core concept in Object-Oriented-Programming that can be used in many different contexts. This blog will be focusing on this concept in the context of building a Rails API. We can get a more clear understanding of this concept by breaking it down into its Greek roots:
If something is polymorphic it has many forms. For example,
numbers in Ruby can be
integers(whole #'s), or
floats(decimal #'s). A polymorphic association in Rails allows you to associate a single model with multiple models through one association declaration (instead of having multiple
Let's say you are building an app that allows users to post content, comment on other posts, and like other posts. Pretty common features that we are all familiar with. Now you want to extend the like feature to comments allowing a user to like individual comments. Your ERD might (or might not) look something like this:
Something like this would work fine, but if you wanted to extend the like feature throughout your app to potential new models in the future you would need to create a separate likes table to the database for each new model you introduce. Overtime this could unnecessarily crowd your database and will end up becoming a repetitive task.
With polymorphic associations we can create a poly_likes table that will act as an interface between other models we want to associate likes to. This isn't the greatest looking ERD but it is looking a little better. Now everytime we want to introduce a new model, we don't need to create a separate likes table to go with that model.
If you're familiar with Rails you know that sticking to naming conventions is part of Rails' magic. To make all of this work, Rails uses "-able" with the class name to name polymorphic associations. Basically what we are doing here is making a comment and a post "likeable". Let's make sure the rest of our models are set up to make all of this work:
PLEASE correct me if I am wrong, but I left out the "as: likeable" from the user model because that would make a user likeable which is not what I want in this situation (who knows maybe you want to allow a user to be liked). In this situation I just want a poly_like to be associated with a specific user.
If you take a close look at the query being generated it is looking for a poly_like that has a user_id which is what I wanted. In these examples I did not create any poly_like seeds so we are getting back an empty array, but we can focus on the queries to see how these associations are working.
- Keeps our code DRY by not having to use a bunch of repetitive
has_manyassociations across all of our models.
- Prevents you from needing to modify existing models and/or adding new join tables to create associations with newly introduced models. (Ex: we did not have to add a separate likes table for the comment & post models like we did in the first ERD.)
- Makes it easier to add new relationships.
- Syntax could take some getting use to at first.
- No foreign keys.
Polymorphism might be a little tricky to wrap your head around at first, but it is really just a fancy word for saying an object can be related to many different types of objects. In my short experience with polymorphism I can see why this a powerful concept but it is probably not necessary for every situation. I am not an expert on this topic and I used this blog as an opportunity to learn an important concept. Please let me know in the comments below if there are any corrections I need to make to this post or if there are some other practical use cases where polymorphism could really come in handy. Hopefully this post made polymorphism more approachable for you. I linked some very helpful resources below that really helped give me a fundamental understanding.
freeCodeCamp blog on polymorphic associations