Rails 4.2: Eager-load has_many relationship with STI

Say I have a relationship in Rails with a table that uses STI, for example:

class Vehicle < ActiveRecord::Base; end

class Car < Vehicle; end

class Truck < Vehicle; end

class Person < ActiveRecord::Base
  has_many :cars
  has_many :trucks
  has_many :vehicles
end

... and I want to load Person and all his cars and trucks in one request. This does not work:

# Generates three queries
p = Person.includes([:cars, trucks]).first

... and it's close, but no luck here:

# Preloads vehicles in one query
p = Person.includes(:vehicles).first
# and this has the correct class (Car or Truck)
p.vehicles.first
# but this still runs another query
p.cars

I could do something like this in person.rb:

def cars
  vehicles.find_all { |v| v.is_a? Car }
end

but then it is Person#carsno longer a collection proxy, and I like the collection proxies.

Is there an elegant solution?

EDIT: adding this to Person gives me the elements I want in single request arrays; this is really very close to what i want:

def vehicle_hash
  @vehicle_hash ||= vehicles.group_by {|v|
    v.type.tableize
  }
end

%w(cars trucks).each do |assoc|
  define_method "#{assoc}_from_hash".to_sym do
    vehicle_hash[assoc] || []
  end
end

and now I can do Person.first.cars_from_hash(or find a better name for my non-synthetic use).

+4
1

includes, association_cache, . p = Person.includes(:vehicles), :vehicles. , .

, p.cars, , :cars association_cache . , :vehicles.

p.vehicles OR p.cars, .

, , - - . , Hash.

, , , , . Person.includes(:cars, :trucks) 3 SQL , .

, , , . , , find_all_cars .

, , , vehicles :

def vehicles(sti_type=nil)
  return super unless sti_type
  super.find_all { |v| v.type == sti_type }
end

vehicles Rails, , , . define_method :

%w(cars trucks).each do |assoc|
  define_method "preloaded_#{assoc}" do
    klass = self.class.reflect_on_all_associations.detect { |assn| assn.name.to_s == assoc }.klass
    vehicles.select { |a| a.is_a? klass }
  end
end

includes, , select ing, where ing. , .

, , , .

+2

All Articles