Fix `SELECT COUNT` queries when rendering ActiveRecord collections (#40870)
* Fix `SELECT COUNT` queries when rendering ActiveRecord collections Fixes #40837 When rendering collections, calling `size` when the collection is an ActiveRecord relation causes unwanted `SELECT COUNT(*)` queries. This change ensures the collection is an array before getting the size, and also loads the relation for any further array inspections. * Test queries when rendering relation collections * Add `length` support to partial collection iterator Allows getting the size of a relation without duplicating records, but still loads the relation. The length method existence needs to be checked because you can pass in an `Enumerator`, which does not respond to `length`. * Ensure unsubscribed from notifications after tests [Rafael Mendonça França + aar0nr]
This commit is contained in:
parent
50bccf249f
commit
432698ef2b
|
@ -47,6 +47,10 @@ module ActionView
|
||||||
def size
|
def size
|
||||||
@collection.size
|
@collection.size
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def length
|
||||||
|
@collection.respond_to?(:length) ? @collection.length : size
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class SameCollectionIterator < CollectionIterator # :nodoc:
|
class SameCollectionIterator < CollectionIterator # :nodoc:
|
||||||
|
@ -144,7 +148,7 @@ module ActionView
|
||||||
"render_collection.action_view",
|
"render_collection.action_view",
|
||||||
identifier: identifier,
|
identifier: identifier,
|
||||||
layout: layout && layout.virtual_path,
|
layout: layout && layout.virtual_path,
|
||||||
count: collection.size
|
count: collection.length
|
||||||
) do |payload|
|
) do |payload|
|
||||||
spacer = if @options.key?(:spacer_template)
|
spacer = if @options.key?(:spacer_template)
|
||||||
spacer_template = find_template(@options[:spacer_template], @locals.keys)
|
spacer_template = find_template(@options[:spacer_template], @locals.keys)
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "active_record_unit"
|
||||||
|
|
||||||
|
class PartialRenderingQueryTest < ActiveRecordTestCase
|
||||||
|
def setup
|
||||||
|
@view = ActionView::Base
|
||||||
|
.with_empty_template_cache
|
||||||
|
.with_view_paths(ActionController::Base.view_paths, {})
|
||||||
|
|
||||||
|
@queries = []
|
||||||
|
|
||||||
|
@subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |*, payload|
|
||||||
|
@queries << payload[:sql] unless %w[ SCHEMA TRANSACTION ].include?(payload[:name])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
ActiveSupport::Notifications.unsubscribe(@subscriber)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_render_with_relation_collection
|
||||||
|
@view.render partial: "topics/topic", collection: Topic.all
|
||||||
|
|
||||||
|
assert_equal 1, @queries.size
|
||||||
|
assert_equal 'SELECT "topics".* FROM "topics"', @queries[0]
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue