Eager loading with scope in Rails

A solution is to use merge with eager_load:

@programs.eager_load(:videos).merge(Video.trailer).map { |p| p.videos.size }

It produces only one query.


As I said, IMO your approach of adding the has_many :trailer_videos, -> { where(video_type: 0) }, class: 'Video' is the simple and best way to counter your problem. I don't see any drawback in adding more such associations to the model.


In Rails Associations have an optional scope parameter that accepts a lambda that is applied to the Relation (see https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many-label-Scopes)

So you could write your models as:

# app/models/video.rb
class Video < ActiveRecord::Base
  belongs_to :program
  scope :trailer, -> { where(video_type: 0) }
  ...
end

# app/models/program.rb
class Program < ActiveRecord::Base
  has_many :videos
  has_many :trailer_videos, -> { trailer }, class: 'Video'
  ...
end

This way you could keep the definition of the scope in Video and reuse it from Program.