Created
August 4, 2017 05:18
-
-
Save hopsoft/f25b804b6adf46910e99a5167adb1a94 to your computer and use it in GitHub Desktop.
Monkey patch for ActiveRecord::CollectionCacheKey
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# MONKEY_PATCH: Override ActiveRecord::CollectionCacheKey#collection_cache_key | |
# This allows us to preserve existing selects when paginating | |
# thus preventing errors when ordering by custom/computed select fields | |
# | |
# For the original implementation SEE: https://github.com/rails/rails/blob/5-0-4/activerecord/lib/active_record/collection_cache_key.rb | |
# IMPORTANT: Upgrade this file whenever upgrading rails versions | |
module ActiveRecord::CollectionCacheKey | |
def collection_cache_key(collection = all, timestamp_column = :updated_at) # :nodoc: | |
query_signature = Digest::MD5.hexdigest(collection.to_sql) | |
key = "#{collection.model_name.cache_key}/query-#{query_signature}" | |
if collection.loaded? | |
size = collection.size | |
if size > 0 | |
timestamp = collection.max_by(×tamp_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" | |
if collection.limit_value || collection.offset_value | |
query = collection.spawn | |
subquery_alias = "subquery_for_cache_key" | |
subquery_column_alias = "subquery_for_cache_key_timestamp_column" | |
query.select_values = [query.select_values.dup, "#{column} AS #{subquery_column_alias}"].flatten | |
subquery = query.arel.as(subquery_alias) | |
arel = Arel::SelectManager.new(subquery).project(select_values % subquery_column_alias) | |
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 | |
timestamp = nil | |
else | |
size = result["size"] | |
timestamp = column_type.deserialize(result["timestamp"]) | |
end | |
end | |
if timestamp | |
"#{key}-#{size}-#{timestamp.utc.to_s(cache_timestamp_format)}" | |
else | |
"#{key}-#{size}" | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment