Skip to content

Commit f2f50c9

Browse files
committed
Fix N+1 on scope with non-image previews
1 parent 5f7bbf2 commit f2f50c9

File tree

2 files changed

+34
-5
lines changed

2 files changed

+34
-5
lines changed

activestorage/app/models/active_storage/attachment.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ class ActiveStorage::Attachment < ActiveStorage::Record
4242
# Eager load all variant records on an attachment at once.
4343
#
4444
# User.first.avatars.with_all_variant_records
45-
scope :with_all_variant_records, -> { includes(blob: { variant_records: { image_attachment: :blob } }) }
45+
scope :with_all_variant_records, -> { includes(blob: {
46+
variant_records: { image_attachment: :blob },
47+
preview_image_attachment: { blob: { variant_records: { image_attachment: :blob } } }
48+
}) }
4649

4750
# Synchronously deletes the attachment and {purges the blob}[rdoc-ref:ActiveStorage::Blob#purge].
4851
def purge

activestorage/test/models/variant_with_record_test.rb

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,30 @@ def test_with_attached_video_variant_no_n_plus_1
153153
find_keys_for_representation "video.mp4"
154154
end
155155

156+
def test_no_n_plus_1_with_all_variant_records_on_attached_video
157+
user = User.create!(name: "Justin")
158+
159+
10.times do
160+
blob = directly_upload_file_blob(filename: "video.mp4")
161+
user.highlights_with_variants.attach(blob)
162+
end
163+
164+
# Force the processing
165+
user.highlights_with_variants.each do |highlight|
166+
highlight.representation(:thumb).processed.key
167+
end
168+
169+
user.reload
170+
171+
highlights = user.highlights_with_variants.with_all_variant_records.to_a
172+
173+
assert_queries_count(0) do
174+
highlights.each do |highlight|
175+
highlight.representation(:thumb).key
176+
end
177+
end
178+
end
179+
156180
test "eager loading has_many_attached records" do
157181
user = User.create!(name: "Josh")
158182

@@ -230,11 +254,12 @@ def test_with_attached_video_variant_no_n_plus_1
230254
user.reload
231255

232256
assert_no_difference -> { ActiveStorage::VariantRecord.count } do
233-
assert_queries_count(5) do
234-
# 5 queries:
257+
assert_queries_count(6) do
258+
# 6 queries:
235259
# attachments (vlogs) x 1
236260
# blobs for the vlogs x 1
237261
# variant records for the blobs x 1
262+
# preview_image_attachments for non-images
238263
# attachments for the variant records x 1
239264
# blobs for the attachments for the variant records x 1
240265
user.vlogs.with_all_variant_records.each do |vlog|
@@ -275,11 +300,12 @@ def test_with_attached_video_variant_no_n_plus_1
275300
# More queries here because we are creating a different variant.
276301
# The second time we load this variant, we are back down to just 3 queries.
277302

278-
assert_queries_match(/SELECT/i, count: 9) do
303+
assert_queries_match(/SELECT/i, count: 10) do
279304
# 9 queries:
280305
# attachments (vlogs) initial load x 1
281306
# blob x 1 (gets both records)
282307
# variant record x 1 (gets both records)
308+
# preview_image_attachments for non-images
283309
# 2x get blob, attachment, variant records again, this happens when loading the new blob inside `VariantWithRecord#key`
284310
user.vlogs.with_all_variant_records.each do |vlog|
285311
rep = vlog.representation(resize_to_limit: [200, 200])
@@ -291,7 +317,7 @@ def test_with_attached_video_variant_no_n_plus_1
291317

292318
user.reload
293319

294-
assert_queries_count(5) do
320+
assert_queries_count(6) do
295321
user.vlogs.with_all_variant_records.each do |vlog|
296322
rep = vlog.representation(resize_to_limit: [200, 200])
297323
rep.processed

0 commit comments

Comments
 (0)