Rails: includes with polymorphic association

Edit 2: I’m now using rails 4.2 and eager loading polymorphism is now a feature 🙂

Edit: This seemed to work in the console, but for some reason, my suggestion of use with the partials below still generates N+1 Query Stack warnings with the bullet gem. I need to investigate…

Ok, I found the solution ([edit] or did I ?), but it assumes that you know all subjects types.

class Activity < ActiveRecord::Base
  belongs_to :subject, polymorphic: true

  belongs_to :event, -> { includes(:activities).where(activities: { subject_type: 'Event' }) }, foreign_key: :subject_id
  belongs_to :image, -> { includes(:activities).where(activities: { subject_type: 'Image' }) }, foreign_key: :subject_id
end

And now you can do

Activity.includes(:part, event: :guests, image: :tags).order(created_at: :desc).limit(10)

But for eager loading to work, you must use for example

activity.event.guests.first

and not

activity.part.guests.first

So you can probably define a method to use instead of subject

def eager_loaded_subject
  public_send(subject.class.to_s.underscore)
end

So now you can have a view with

render partial: :subject, collection: activity

A partial with

# _activity.html.erb
render :partial => 'activities/' + activity.subject_type.underscore, object: activity.eager_loaded_subject

And two (dummy) partials

# _event.html.erb
<p><%= event.guests.map(&:name).join(', ') %></p>

# _image.html.erb
<p><%= image.tags.first.map(&:name).join(', ') %></p>

Leave a Comment

tech