With polymorphism
class Image < ActiveRecord::Base
belongs_to :illustrable, polymorphic: true
end
class Post < ActiveRecord::Base
has_many :images, as: :illustrable
has_many :comments
end
class Comment < ActiveRecord::Base
has_many :images, as: :illustrable
end
I can preload dependent association thanks to Support preloads on instance dependent associations by jhawthorn · Pull Request #42553 · rails/rails · GitHub
Image.includes(illustrable: :comments).to_a
With STI
class Post < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :post
end
class TextComment < Comment
end
class VideoComment < Comment
belongs_to :video
end
class Video < ActiveRecord::Base
has_many :comments
end
I can’t
Post.preload(comments: :video).to_a
ActiveRecord::AssociationNotFoundError: Association named 'video' was not found on Comment; perhaps you misspelled it?
I tried to patch, just for a test lib/active_record/associations/preloader/branch.rb#grouped_records
def grouped_records
h = {}
polymorphic_parent = !root? && parent.polymorphic?
source_records.each do |record|
reflection = record.class._reflect_on_association(association)
next if !reflection
next if !record.association(association).klass
(h[reflection] ||= []) << record
end
source_records.first.association(association) if !source_records.empty? && h.empty? && !polymorphic_parent
h
end
But It doesn’t work if source_records are not records having the relations:
test "preloading of instance dependent (sti) associations is supported" do
pirate_1 = Pirate.create!(catchphrase: "Yarr")
pirate_2 = Pirate.create!(catchphrase: "Ahoy")
parrot = Parrot.create!(name: "Polly 1", pirates: [pirate_1])
parrot = Parrot.create!(name: "Polly 2", pirates: [pirate_2])
dparrot = DeadParrot.create!(killer: pirate_1, name: "D Polly 2", pirates: [pirate_2])
pirate = Pirate.preload(parrots: :killer).find(pirate_2.id)
assert_queries_count(0) {
assert_equal pirate_1, pirate.parrots.second.killer
}
assert_equal [], Pirate.none.preload(parrots: :killer).to_a
assert_equal pirate_1, Pirate.where(id: pirate_1.id).preload(parrots: :killer).first
end
The last test fail
Do you see a better way to do it ? Ideally a test like parent.polymorphic? which say that source_records are STI records
Thanks