felipeecst
felipeecst

Reputation: 1415

ActiveRecord - nested includes

I'm trying to perform the following query in Rails 5 in a way that it doesn't trigger N+1 queries when I access each events.contact:

events = @company.recipients_events
                 .where(contacts: { user_id: user_id })

I tried some combinations of .includes, .references and .eager_loading, but none of them worked. Some of them returned an SQL error, and other ones returned a nil object when I access events.contact.

Here's a brief version of my associations:

class Company
   has_many :recipients
   has_many :recipients_events, through: :recipients, source: :events
end

class Recipient
   belongs_to :contact
   has_many :events, as: :eventable
end

class Event
   belongs_to :eventable, polymorphic: true
end

class Contact
   has_many :recipients
end

What would be the correct way to achieve what I need?

Upvotes: 3

Views: 3963

Answers (1)

Jacob Vanus
Jacob Vanus

Reputation: 569

If you already know user_id when you load @company, I'd do something like this:

@company = Company.where(whatever)
  .includes(recipients: [:recipients_events, :contact])
  .where(contacts: { user_id: user_id })
  .take
events = @company.recipients_events

OR, if not:

events = Company.where(whatever)
  .includes(recipients: [:recipients_events, :contact])
  .where(contacts: { user_id: user_id })
  .take
  .recipients_events

The ActiveRecord query planner will determine what it thinks is the best way to get that data. It might be 1 query per table without the where, but when you chain includes().where() you will probably get 2 queries both with left outer joins on them.

Upvotes: 3

Related Questions