diff --git a/CHANGELOG.md b/CHANGELOG.md index f0c937a3..3098b943 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ Fixes: Misc: +- [#1878](https://github.com/rails-api/active_model_serializers/pull/1878) Cache key generation for serializers now uses `ActiveSupport::Cache.expand_cache_key` instead of `Array#join` by default and is also overridable. This change should be backward-compatible. (@markiz) + ### [v0.10.2 (2016-07-05)](https://github.com/rails-api/active_model_serializers/compare/v0.10.1...v0.10.2) Fixes: diff --git a/lib/active_model/serializer/caching.rb b/lib/active_model/serializer/caching.rb index 20362ce8..4809f4cb 100644 --- a/lib/active_model/serializer/caching.rb +++ b/lib/active_model/serializer/caching.rb @@ -263,7 +263,11 @@ module ActiveModel parts << object_cache_key parts << adapter_instance.cache_key parts << serializer_class._cache_digest unless serializer_class._skip_digest? - @cache_key = parts.join('/') + @cache_key = expand_cache_key(parts) + end + + def expand_cache_key(parts) + ActiveSupport::Cache.expand_cache_key(parts) end # Use object's cache_key if available, else derive a key from the object diff --git a/test/cache_test.rb b/test/cache_test.rb index 64e93f80..c0770cda 100644 --- a/test/cache_test.rb +++ b/test/cache_test.rb @@ -4,6 +4,30 @@ require 'tempfile' module ActiveModelSerializers class CacheTest < ActiveSupport::TestCase + # Instead of a primitive cache key (i.e. a string), this class + # returns a list of objects that require to be expanded themselves. + class AuthorWithExpandableCacheElements < Author + # For the test purposes it's important that #to_s for HasCacheKey differs + # between instances, hence not a Struct. + class HasCacheKey + attr_reader :cache_key + def initialize(cache_key) + @cache_key = cache_key + end + + def to_s + "HasCacheKey##{object_id}" + end + end + + def cache_key + [ + HasCacheKey.new(name), + HasCacheKey.new(id) + ] + end + end + class UncachedAuthor < Author # To confirm cache_key is set using updated_at and cache_key option passed to cache undef_method :cache_key @@ -106,6 +130,20 @@ module ActiveModelSerializers assert_equal(uncached_author_serializer.attributes.to_json, cache_store.fetch(key).to_json) end + def test_cache_key_expansion + author = AuthorWithExpandableCacheElements.new(id: 10, name: 'hello') + same_author = AuthorWithExpandableCacheElements.new(id: 10, name: 'hello') + diff_author = AuthorWithExpandableCacheElements.new(id: 11, name: 'hello') + + author_serializer = AuthorSerializer.new(author) + same_author_serializer = AuthorSerializer.new(same_author) + diff_author_serializer = AuthorSerializer.new(diff_author) + adapter = AuthorSerializer.serialization_adapter_instance + + assert_equal(author_serializer.cache_key(adapter), same_author_serializer.cache_key(adapter)) + refute_equal(author_serializer.cache_key(adapter), diff_author_serializer.cache_key(adapter)) + end + def test_default_cache_key_fallback render_object_with_cache(@comment) key = "#{@comment.cache_key}/#{adapter.cache_key}"