Posted over 7 years ago. Visible to the public. Repeats.

Preloaded associations are filtered by conditions on the same table

When you eagerly load an association list using the :include option, and at the same time have a :condition on an included table, two things happen:

  1. Rails 2, 3, 4, 5 tries to load all involved records in a huge single query spanning multiple database tables.
  2. The preloaded association list is filtered by the :condition, even though you only wanted to use the :condition to filter the containing model.

The second case's behavior is mostly unexpected, because pre-loaded associations usually don't care about the circumstances under which their containing model was found.

Example

Take this class:

Copy
class Activity has_many :users end

Here activity 42 has four users:

Copy
activity = Activity.find(42) activity.users.collect(&:id) # => [1, 2, 3, 4]

Let's say we want to do the same on all activities that belong to a user. To this, we scope on Activity.
Note how the activity from above now suddenly no longer contains any other users:

Copy
activity = Activity. scoped( :conditions => { :users => { :id => [4] } }, :include => :users ). find(42) activity.users.collect(&:id) # here happens the unexpected # => [4]

By reloading the object, its full list of associated users is restored:

Copy
activity.reload.users.collect(&:id) # => [1, 2, 3, 4]

Or you can reset the association cache:

Copy
activity.users.reset # newer Rails activity.users(true) # old Rails

In newer Rails versions you should prefer to use joins and then preload if necessary (which will trigger a second query):

Copy
# Join for the condition, but do not preload activities = Activity.joins(:users).where(users: { id: [4] }) # Preload associations with a second query on users; # Does not make a join. activities = activities.preload(:users)
Growing Rails Applications in Practice
Check out our new e-book:
Learn to structure large Ruby on Rails codebases with the tools you already know and love.

Author of this card:

Avatar
Arne Hartherz
Last edit:
6 months ago
by Henning Koch
Keywords:
join, joins, has_many
About this deck:
We are makandra and do test-driven, agile Ruby on Rails software development.
License for source code
Posted by Arne Hartherz to makandra dev