aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
authorRafael França <rafaelmfranca@gmail.com>2017-04-19 21:02:07 -0400
committerGitHub <noreply@github.com>2017-04-19 21:02:07 -0400
commitd87d0e34dae7511b234058d374507721843dc8ee (patch)
treea1e211359a20284969a1e53131906ed9bd86bb53 /activerecord
parente8b4a927340183acba7fd0a2c3864afc2388a9aa (diff)
parentc2dbdd814097031d437aca06f46032c8111d4880 (diff)
downloadrails-d87d0e34dae7511b234058d374507721843dc8ee.tar.gz
rails-d87d0e34dae7511b234058d374507721843dc8ee.tar.bz2
rails-d87d0e34dae7511b234058d374507721843dc8ee.zip
Merge pull request #28776 from kamipo/respect_limit_for_cache_key
`cache_key` respects the limit in a relation even if a relation is not loaded
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/lib/active_record/collection_cache_key.rb22
-rw-r--r--activerecord/test/cases/collection_cache_key_test.rb30
2 files changed, 44 insertions, 8 deletions
diff --git a/activerecord/lib/active_record/collection_cache_key.rb b/activerecord/lib/active_record/collection_cache_key.rb
index 43784b70e3..1e1de1863a 100644
--- a/activerecord/lib/active_record/collection_cache_key.rb
+++ b/activerecord/lib/active_record/collection_cache_key.rb
@@ -7,17 +7,27 @@ module ActiveRecord
if collection.loaded?
size = collection.size
if size > 0
- timestamp = collection.max_by(&timestamp_column).public_send(timestamp_column)
+ timestamp = collection.max_by(&timestamp_column)._read_attribute(timestamp_column)
end
else
column_type = type_for_attribute(timestamp_column.to_s)
column = "#{connection.quote_table_name(collection.table_name)}.#{connection.quote_column_name(timestamp_column)}"
+ select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
- query = collection
- .unscope(:select)
- .select("COUNT(*) AS #{connection.quote_column_name("size")}", "MAX(#{column}) AS timestamp")
- .unscope(:order)
- result = connection.select_one(query)
+ if collection.limit_value || collection.offset_value
+ query = collection.spawn
+ query.select_values = [column]
+ subquery_alias = "subquery_for_cache_key"
+ subquery_column = "#{subquery_alias}.#{timestamp_column}"
+ subquery = query.arel.as(subquery_alias)
+ arel = Arel::SelectManager.new(query.engine).project(select_values % subquery_column).from(subquery)
+ else
+ query = collection.unscope(:order)
+ query.select_values = [select_values % column]
+ arel = query.arel
+ end
+
+ result = connection.select_one(arel, nil, query.bound_attributes)
if result.blank?
size = 0
diff --git a/activerecord/test/cases/collection_cache_key_test.rb b/activerecord/test/cases/collection_cache_key_test.rb
index 381a78a8e2..92620761e4 100644
--- a/activerecord/test/cases/collection_cache_key_test.rb
+++ b/activerecord/test/cases/collection_cache_key_test.rb
@@ -15,8 +15,34 @@ module ActiveRecord
end
test "cache_key for relation" do
- developers = Developer.where(name: "David")
- last_developer_timestamp = developers.order(updated_at: :desc).first.updated_at
+ developers = Developer.where(salary: 100000).order(updated_at: :desc)
+ last_developer_timestamp = developers.first.updated_at
+
+ assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/, developers.cache_key)
+
+ /\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/ =~ developers.cache_key
+
+ assert_equal Digest::MD5.hexdigest(developers.to_sql), $1
+ assert_equal developers.count.to_s, $2
+ assert_equal last_developer_timestamp.to_s(ActiveRecord::Base.cache_timestamp_format), $3
+ end
+
+ test "cache_key for relation with limit" do
+ developers = Developer.where(salary: 100000).order(updated_at: :desc).limit(5)
+ last_developer_timestamp = developers.first.updated_at
+
+ assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/, developers.cache_key)
+
+ /\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/ =~ developers.cache_key
+
+ assert_equal Digest::MD5.hexdigest(developers.to_sql), $1
+ assert_equal developers.count.to_s, $2
+ assert_equal last_developer_timestamp.to_s(ActiveRecord::Base.cache_timestamp_format), $3
+ end
+
+ test "cache_key for loaded relation" do
+ developers = Developer.where(salary: 100000).order(updated_at: :desc).limit(5).load
+ last_developer_timestamp = developers.first.updated_at
assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/, developers.cache_key)