Query on polymorphic association

  • Jun 23

Assume you have these association:

  1. a user has many likes
  2. a like is associated to either article or comment

Therefore, a Like model look like this:

class Like < ActiveRecord::Base
  belongs_to :user
  belongs_to :likable, polymorphic: true
end

Article and comment are all likable.

You can search content of article belonging to a given user like this:

Article.joins(likables: :user).where("users.id = ?", current_user.id)

What if you want to search both article and comment at the same time ? The key is LEFT JOIN.

You need to chain Like, Article and Comment together, then you can search on article and comment at the same time.

To chain them together, try this:

likes = Like.joins("LEFT OUTER JOIN articles on likes.likable_id = articles.id AND likes.likable_type = \'Article\'").joins("LEFT OUTER JOIN comments on likes.likable_id = comments.id AND likes.likable_type = \'Comment\'")

Now, both articles and comments are included, you can search easy:

likes.where("articles.title = ? OR comments.title = ?", "title", "title")

It works in ActiveRecord Relation and can be chained easily. For example, you can even eager-load likable

likes.where("articles.title = ? OR comments.title = ?", "title", "title").includes(:likable)

Then iterate likes to get all matched articles and comments.