Jochen Ullrich
Jochen Ullrich

Reputation: 578

Filter Active Record by relation but not the relation itself

I would like to filter a model with a has_many relation by a value of it's relation.

This is easily achievable by using Foo.include(:bars).where(bars: { foobar: 2 }).

If we had an object like this in our database:

{
  id: 1,
  bars: [
    { id: 4, foobar: 1 },
    { id: 5, foobar: 2 }
  ]
}

This query would only return this:

{
  id: 1,
  bars: [
    { id: 5, foobar: 2 }
  ]
}

I would like to still filter my records by this relation, but receive all records in the relation.

I was able to achieve this by using something like: Foo.include(:bars).joins('LEFT JOIN bars AS filtered_bars ON filtered_bars.foo_id = foos.id').where(filtered_bars: { foobar: 2 }) but this does not look very pretty.

Is there a better way to do this?

Upvotes: 2

Views: 99

Answers (1)

BroiSatse
BroiSatse

Reputation: 44675

This is the magic of includes in action - since you are using bar in where, it decides to use a left join and will not preload anything else. You have to explicitly join and prelaod the association here:

Foo.joins(:bars).where(bars: {foobar: 2}).uniq.preload(:bars)

Some time ago I made a talk on those magic methods, you can find it here: https://skillsmatter.com/skillscasts/6731-activerecord-vs-n-1

Upvotes: 2

Related Questions