Reputation: 51
class Foo < ActiveRecord::Base
has_many :bars
end
class Bar < ActiveRecord::Base
belongs_to :foo
def self.activated
where(activated: true)
end
end
class FoosController < ApplicationController
def index
@foos = Foo.includes(:bars)
end
end
Let's say I want to display a table of all Foos, including the number of activated bars on it. To prevent N+1 queries, I already include(s) :bars when retrieving all Foos. However, If I use foo.bars.activated
, Rails fires up another query, not knowing about the already retrieved bars.
I see two options here:
foo.bars.select(&:activated)
has_many :activated_bars, -> { where(activated: true) }, class_name: 'Bar'
Are there other (better) ways to do this?
Upvotes: 1
Views: 53
Reputation: 8044
The following will load all foo's with only activated bars and also eager_load the bars
Foo.eager_load(:bars).merge(Bar.activated)
Updated:
Or you might also define a new scoped relationship on Foo and eager_load that
#Foo
has_many :activated_bars, ->{ activated }, clas_name: 'Bar'
#foos_controller#index
Foo.includes(:activated_bars)
See also http://blog.bigbinary.com/2013/07/01/preload-vs-eager-load-vs-joins-vs-includes.html
Upvotes: 1