When you have different models sharing the same join table in Ruby on Rails, you can create a polymorphic has_many through relationship without a hassle.

The Problem

Let’s suppose that you have Task, Project and Group models and all have them have multiple members, i.e. Users. One solution is to define a seperate membership model for all models :

Yet in this solution, you’re clearly violating DRY principle, repeating common code in different models.

The Solution

A better solution might be having a polymorphic membership model for all models which have a membership :

The reason we’re using source and source_type on User model for polymorphic has_many through is Rails doesn’t know which association to look for on the join model without knowing the type of source.

Yet we can further DRY our code by writing a concern instead of repeating same code on models :

Note that since Membership is not created automatically on new Group or Project creation, we’re using an after_create callback for the person who creates a group or project, thus making them members.

This way, you can call @user.first.groups or user.first.projects conveniently from the same membership model, without repeating yourself.

Happy coding.