diff --git a/lib/active_model/serializer/caching.rb b/lib/active_model/serializer/caching.rb
index 077cb569..60c7ef70 100644
--- a/lib/active_model/serializer/caching.rb
+++ b/lib/active_model/serializer/caching.rb
@@ -1,5 +1,6 @@
module ActiveModel
class Serializer
+ UndefinedCacheKey = Class.new(StandardError)
module Caching
extend ActiveSupport::Concern
@@ -62,6 +63,14 @@ module ActiveModel
_cache_options && _cache_options[:skip_digest]
end
+ def cached_attributes
+ _cache_only ? _cache_only : _attributes - _cache_except
+ end
+
+ def non_cached_attributes
+ _attributes - cached_attributes
+ end
+
# @api private
# Used by FragmentCache on the CachedSerializer
# to call attribute methods on the fragmented cached serializer.
@@ -145,6 +154,173 @@ module ActiveModel
perform_caching? && cache_store &&
(_cache_only && !_cache_except || !_cache_only && _cache_except)
end
+
+ # Read cache from cache_store
+ # @return [Hash]
+ def cache_read_multi(collection_serializer, adapter_instance, include_tree)
+ return {} if ActiveModelSerializers.config.cache_store.blank?
+
+ keys = object_cache_keys(collection_serializer, adapter_instance, include_tree)
+
+ return {} if keys.blank?
+
+ ActiveModelSerializers.config.cache_store.read_multi(*keys)
+ end
+
+ # Find all cache_key for the collection_serializer
+ # @param serializers [ActiveModel::Serializer::CollectionSerializer]
+ # @param adapter_instance [ActiveModelSerializers::Adapter::Base]
+ # @param include_tree [ActiveModel::Serializer::IncludeTree]
+ # @return [Array] all cache_key of collection_serializer
+ def object_cache_keys(collection_serializer, adapter_instance, include_tree)
+ cache_keys = []
+
+ collection_serializer.each do |serializer|
+ cache_keys << object_cache_key(serializer, adapter_instance)
+
+ serializer.associations(include_tree).each do |association|
+ if association.serializer.respond_to?(:each)
+ association.serializer.each do |sub_serializer|
+ cache_keys << object_cache_key(sub_serializer, adapter_instance)
+ end
+ else
+ cache_keys << object_cache_key(association.serializer, adapter_instance)
+ end
+ end
+ end
+
+ cache_keys.compact.uniq
+ end
+
+ # @return [String, nil] the cache_key of the serializer or nil
+ def object_cache_key(serializer, adapter_instance)
+ return unless serializer.present? && serializer.object.present?
+
+ serializer.class.cache_enabled? ? serializer.cache_key(adapter_instance) : nil
+ end
+ end
+
+ # Get attributes from @cached_attributes
+ # @return [Hash] cached attributes
+ # def cached_attributes(fields, adapter_instance)
+ def cached_fields(fields, adapter_instance)
+ cache_check(adapter_instance) do
+ attributes(fields)
+ end
+ end
+
+ def cache_check(adapter_instance)
+ if self.class.cache_enabled?
+ self.class.cache_store.fetch(cache_key(adapter_instance), self.class._cache_options) do
+ yield
+ end
+ elsif self.class.fragment_cache_enabled?
+ fetch_fragment_cache(adapter_instance)
+ else
+ yield
+ end
+ end
+
+ # 1. Create a CachedSerializer and NonCachedSerializer from the serializer class
+ # 2. Serialize the above two with the given adapter
+ # 3. Pass their serializations to the adapter +::fragment_cache+
+ #
+ # It will split the serializer into two, one that will be cached and one that will not
+ #
+ # Given a resource name
+ # 1. Dynamically creates a CachedSerializer and NonCachedSerializer
+ # for a given class 'name'
+ # 2. Call
+ # CachedSerializer.cache(serializer._cache_options)
+ # CachedSerializer.fragmented(serializer)
+ # NonCachedSerializer.cache(serializer._cache_options)
+ # 3. Build a hash keyed to the +cached+ and +non_cached+ serializers
+ # 4. Call +cached_attributes+ on the serializer class and the above hash
+ # 5. Return the hash
+ #
+ # @example
+ # When +name+ is User::Admin
+ # creates the Serializer classes (if they don't exist).
+ # CachedUser_AdminSerializer
+ # NonCachedUser_AdminSerializer
+ #
+ # Given a hash of its cached and non-cached serializers
+ # 1. Determine cached attributes from serializer class options
+ # 2. Add cached attributes to cached Serializer
+ # 3. Add non-cached attributes to non-cached Serializer
+ def fetch_fragment_cache(adapter_instance)
+ serializer_class_name = self.class.name.gsub('::'.freeze, '_'.freeze)
+ self.class._cache_options ||= {}
+ self.class._cache_options[:key] = self.class._cache_key if self.class._cache_key
+
+ cached_serializer = _get_or_create_fragment_cached_serializer(serializer_class_name)
+ cached_hash = ActiveModelSerializers::SerializableResource.new(
+ object,
+ serializer: cached_serializer,
+ adapter: adapter_instance.class
+ ).serializable_hash
+
+ non_cached_serializer = _get_or_create_fragment_non_cached_serializer(serializer_class_name)
+ non_cached_hash = ActiveModelSerializers::SerializableResource.new(
+ object,
+ serializer: non_cached_serializer,
+ adapter: adapter_instance.class
+ ).serializable_hash
+
+ # Merge both results
+ adapter_instance.fragment_cache(cached_hash, non_cached_hash)
+ end
+
+ def _get_or_create_fragment_cached_serializer(serializer_class_name)
+ cached_serializer = _get_or_create_fragment_serializer "Cached#{serializer_class_name}"
+ cached_serializer.cache(self.class._cache_options)
+ cached_serializer.type(self.class._type)
+ cached_serializer.fragmented(self)
+ self.class.cached_attributes.each do |attribute|
+ options = self.class._attributes_keys[attribute] || {}
+ cached_serializer.attribute(attribute, options)
+ end
+ cached_serializer
+ end
+
+ def _get_or_create_fragment_non_cached_serializer(serializer_class_name)
+ non_cached_serializer = _get_or_create_fragment_serializer "NonCached#{serializer_class_name}"
+ non_cached_serializer.type(self.class._type)
+ non_cached_serializer.fragmented(self)
+ self.class.non_cached_attributes.each do |attribute|
+ options = self.class._attributes_keys[attribute] || {}
+ non_cached_serializer.attribute(attribute, options)
+ end
+ non_cached_serializer
+ end
+
+ def _get_or_create_fragment_serializer(name)
+ return Object.const_get(name) if Object.const_defined?(name)
+ Object.const_set(name, Class.new(ActiveModel::Serializer))
+ end
+
+ def cache_key(adapter_instance)
+ return @cache_key if defined?(@cache_key)
+
+ parts = []
+ parts << object_cache_key
+ parts << adapter_instance.cached_name
+ parts << self.class._cache_digest unless self.class._skip_digest?
+ @cache_key = parts.join('/')
+ end
+
+ # Use object's cache_key if available, else derive a key from the object
+ # Pass the `key` option to the `cache` declaration or override this method to customize the cache key
+ def object_cache_key
+ if object.respond_to?(:cache_key)
+ object.cache_key
+ elsif (serializer_cache_key = (self.class._cache_key || self.class._cache_options[:key]))
+ object_time_safe = object.updated_at
+ object_time_safe = object_time_safe.strftime('%Y%m%d%H%M%S%9N') if object_time_safe.respond_to?(:strftime)
+ "#{serializer_cache_key}/#{object.id}-#{object_time_safe}"
+ else
+ fail UndefinedCacheKey, "#{object.class} must define #cache_key, or the 'key:' option must be passed into '#{self.class}.cache'"
+ end
end
end
end
diff --git a/lib/active_model_serializers.rb b/lib/active_model_serializers.rb
index 15551f4b..6241fac1 100644
--- a/lib/active_model_serializers.rb
+++ b/lib/active_model_serializers.rb
@@ -6,8 +6,6 @@ require 'active_support/json'
module ActiveModelSerializers
extend ActiveSupport::Autoload
autoload :Model
- autoload :CachedSerializer
- autoload :FragmentCache
autoload :Callbacks
autoload :Deserialization
autoload :SerializableResource
diff --git a/lib/active_model_serializers/adapter/attributes.rb b/lib/active_model_serializers/adapter/attributes.rb
index 95189233..50e958f1 100644
--- a/lib/active_model_serializers/adapter/attributes.rb
+++ b/lib/active_model_serializers/adapter/attributes.rb
@@ -25,33 +25,6 @@ module ActiveModelSerializers
serializer.map { |s| Attributes.new(s, instance_options).serializable_hash(options) }
end
- # Read cache from cache_store
- # @return [Hash]
- def cache_read_multi
- return {} if ActiveModelSerializers.config.cache_store.blank?
-
- keys = CachedSerializer.object_cache_keys(serializer, self, @include_tree)
-
- return {} if keys.blank?
-
- ActiveModelSerializers.config.cache_store.read_multi(*keys)
- end
-
- # Set @cached_attributes
- def cache_attributes
- return if @cached_attributes.present?
-
- @cached_attributes = cache_read_multi
- end
-
- # Get attributes from @cached_attributes
- # @return [Hash] cached attributes
- def cached_attributes(cached_serializer)
- return yield unless cached_serializer.cached?
-
- @cached_attributes.fetch(cached_serializer.cache_key(self)) { yield }
- end
-
def serializable_hash_for_single_resource(options)
resource = resource_object_for(options)
relationships = resource_relationships(options)
@@ -80,13 +53,20 @@ module ActiveModelSerializers
json
end
- def resource_object_for(options)
- cached_serializer = CachedSerializer.new(serializer)
+ # Set @cached_attributes
+ def cache_attributes
+ return if @cached_attributes.present?
- cached_attributes(cached_serializer) do
- cached_serializer.cache_check(self) do
- serializer.attributes(options[:fields])
+ @cached_attributes = ActiveModel::Serializer.cache_read_multi(serializer, self, @include_tree)
+ end
+
+ def resource_object_for(options)
+ if serializer.class.cache_enabled?
+ @cached_attributes.fetch(serializer.cache_key(self)) do
+ serializer.cached_fields(options[:fields], self)
end
+ else
+ serializer.cached_fields(options[:fields], self)
end
end
end
diff --git a/lib/active_model_serializers/adapter/base.rb b/lib/active_model_serializers/adapter/base.rb
index 9b15c6ff..1a366139 100644
--- a/lib/active_model_serializers/adapter/base.rb
+++ b/lib/active_model_serializers/adapter/base.rb
@@ -36,7 +36,7 @@ module ActiveModelSerializers
end
def cache_check(serializer)
- CachedSerializer.new(serializer).cache_check(self) do
+ serializer.cache_check(self) do
yield
end
end
diff --git a/lib/active_model_serializers/cached_serializer.rb b/lib/active_model_serializers/cached_serializer.rb
deleted file mode 100644
index 09b906ed..00000000
--- a/lib/active_model_serializers/cached_serializer.rb
+++ /dev/null
@@ -1,87 +0,0 @@
-module ActiveModelSerializers
- class CachedSerializer
- UndefinedCacheKey = Class.new(StandardError)
-
- def initialize(serializer)
- @cached_serializer = serializer
- @klass = @cached_serializer.class
- end
-
- def cache_check(adapter_instance)
- if cached?
- @klass._cache.fetch(cache_key(adapter_instance), @klass._cache_options) do
- yield
- end
- elsif fragment_cached?
- FragmentCache.new(adapter_instance, @cached_serializer, adapter_instance.instance_options).fetch
- else
- yield
- end
- end
-
- def cached?
- @klass.cache_enabled?
- end
-
- def fragment_cached?
- @klass.fragment_cache_enabled?
- end
-
- def cache_key(adapter_instance)
- return @cache_key if defined?(@cache_key)
-
- parts = []
- parts << object_cache_key
- parts << adapter_instance.cached_name
- parts << @klass._cache_digest unless @klass._skip_digest?
- @cache_key = parts.join('/')
- end
-
- # Use object's cache_key if available, else derive a key from the object
- # Pass the `key` option to the `cache` declaration or override this method to customize the cache key
- def object_cache_key
- if @cached_serializer.object.respond_to?(:cache_key)
- @cached_serializer.object.cache_key
- elsif (cache_key = (@klass._cache_key || @klass._cache_options[:key]))
- object_time_safe = @cached_serializer.object.updated_at
- object_time_safe = object_time_safe.strftime('%Y%m%d%H%M%S%9N') if object_time_safe.respond_to?(:strftime)
- "#{cache_key}/#{@cached_serializer.object.id}-#{object_time_safe}"
- else
- fail UndefinedCacheKey, "#{@cached_serializer.object.class} must define #cache_key, or the 'key:' option must be passed into '#{@klass}.cache'"
- end
- end
-
- # find all cache_key for the collection_serializer
- # @param serializers [ActiveModel::Serializer::CollectionSerializer]
- # @param adapter_instance [ActiveModelSerializers::Adapter::Base]
- # @param include_tree [ActiveModel::Serializer::IncludeTree]
- # @return [Array] all cache_key of collection_serializer
- def self.object_cache_keys(serializers, adapter_instance, include_tree)
- cache_keys = []
-
- serializers.each do |serializer|
- cache_keys << object_cache_key(serializer, adapter_instance)
-
- serializer.associations(include_tree).each do |association|
- if association.serializer.respond_to?(:each)
- association.serializer.each do |sub_serializer|
- cache_keys << object_cache_key(sub_serializer, adapter_instance)
- end
- else
- cache_keys << object_cache_key(association.serializer, adapter_instance)
- end
- end
- end
-
- cache_keys.compact.uniq
- end
-
- # @return [String, nil] the cache_key of the serializer or nil
- def self.object_cache_key(serializer, adapter_instance)
- return unless serializer.present? && serializer.object.present?
-
- cached_serializer = new(serializer)
- cached_serializer.cached? ? cached_serializer.cache_key(adapter_instance) : nil
- end
- end
-end
diff --git a/lib/active_model_serializers/fragment_cache.rb b/lib/active_model_serializers/fragment_cache.rb
deleted file mode 100644
index 78f0f278..00000000
--- a/lib/active_model_serializers/fragment_cache.rb
+++ /dev/null
@@ -1,118 +0,0 @@
-module ActiveModelSerializers
- class FragmentCache
- attr_reader :serializer
-
- def initialize(adapter, serializer, options)
- @instance_options = options
- @adapter = adapter
- @serializer = serializer
- end
-
- # 1. Create a CachedSerializer and NonCachedSerializer from the serializer class
- # 2. Serialize the above two with the given adapter
- # 3. Pass their serializations to the adapter +::fragment_cache+
- def fetch
- object = serializer.object
-
- # It will split the serializer into two, one that will be cached and one that will not
- serializers = fragment_serializer
-
- # Get serializable hash from both
- cached_hash = serialize(object, serializers[:cached])
- non_cached_hash = serialize(object, serializers[:non_cached])
-
- # Merge both results
- adapter.fragment_cache(cached_hash, non_cached_hash)
- end
-
- protected
-
- attr_reader :instance_options, :adapter
-
- private
-
- def serialize(object, serializer_class)
- SerializableResource.new(
- object,
- serializer: serializer_class,
- adapter: adapter.class
- ).serializable_hash
- end
-
- # Given a hash of its cached and non-cached serializers
- # 1. Determine cached attributes from serializer class options
- # 2. Add cached attributes to cached Serializer
- # 3. Add non-cached attributes to non-cached Serializer
- def cache_attributes(serializers)
- klass = serializer.class
- attributes = klass._attributes
- cache_only = klass._cache_only
- cached_attributes = cache_only ? cache_only : attributes - klass._cache_except
- non_cached_attributes = attributes - cached_attributes
- attributes_keys = klass._attributes_keys
-
- add_attributes_to_serializer(serializers[:cached], cached_attributes, attributes_keys)
- add_attributes_to_serializer(serializers[:non_cached], non_cached_attributes, attributes_keys)
- end
-
- def add_attributes_to_serializer(serializer, attributes, attributes_keys)
- attributes.each do |attribute|
- options = attributes_keys[attribute] || {}
- serializer.attribute(attribute, options)
- end
- end
-
- # Given a resource name
- # 1. Dynamically creates a CachedSerializer and NonCachedSerializer
- # for a given class 'name'
- # 2. Call
- # CachedSerializer.cache(serializer._cache_options)
- # CachedSerializer.fragmented(serializer)
- # NonCachedSerializer.cache(serializer._cache_options)
- # 3. Build a hash keyed to the +cached+ and +non_cached+ serializers
- # 4. Call +cached_attributes+ on the serializer class and the above hash
- # 5. Return the hash
- #
- # @example
- # When +name+ is User::Admin
- # creates the Serializer classes (if they don't exist).
- # CachedUser_AdminSerializer
- # NonCachedUser_AdminSerializer
- #
- def fragment_serializer
- klass = serializer.class
- serializer_class_name = to_valid_const_name(klass.name)
-
- cached = "Cached#{serializer_class_name}"
- non_cached = "NonCached#{serializer_class_name}"
-
- cached_serializer = get_or_create_serializer(cached)
- non_cached_serializer = get_or_create_serializer(non_cached)
-
- klass._cache_options ||= {}
- cache_key = klass._cache_key
- klass._cache_options[:key] = cache_key if cache_key
- cached_serializer.cache(klass._cache_options)
-
- type = klass._type
- cached_serializer.type(type)
- non_cached_serializer.type(type)
-
- non_cached_serializer.fragmented(serializer)
- cached_serializer.fragmented(serializer)
-
- serializers = { cached: cached_serializer, non_cached: non_cached_serializer }
- cache_attributes(serializers)
- serializers
- end
-
- def get_or_create_serializer(name)
- return Object.const_get(name) if Object.const_defined?(name)
- Object.const_set(name, Class.new(ActiveModel::Serializer))
- end
-
- def to_valid_const_name(name)
- name.gsub('::', '_')
- end
- end
-end
diff --git a/test/active_model_serializers/cached_serializer_test.rb b/test/active_model_serializers/cached_serializer_test.rb
deleted file mode 100644
index e9b3ff45..00000000
--- a/test/active_model_serializers/cached_serializer_test.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-require 'test_helper'
-module ActiveModelSerializers
- module Adapter
- class CachedSerializerTest < ActiveSupport::TestCase
- def test_cached_false_without_cache_store
- cached_serializer = build do |serializer|
- serializer._cache = nil
- end
- refute cached_serializer.cached?
- end
-
- def test_cached_true_with_cache_store_and_without_cache_only_and_cache_except
- cached_serializer = build do |serializer|
- serializer._cache = Object
- end
- assert cached_serializer.cached?
- end
-
- def test_cached_false_with_cache_store_and_with_cache_only
- cached_serializer = build do |serializer|
- serializer._cache = Object
- serializer._cache_only = [:name]
- end
- refute cached_serializer.cached?
- end
-
- def test_cached_false_with_cache_store_and_with_cache_except
- cached_serializer = build do |serializer|
- serializer._cache = Object
- serializer._cache_except = [:content]
- end
- refute cached_serializer.cached?
- end
-
- def test_fragment_cached_false_without_cache_store
- cached_serializer = build do |serializer|
- serializer._cache = nil
- serializer._cache_only = [:name]
- end
- refute cached_serializer.fragment_cached?
- end
-
- def test_fragment_cached_true_with_cache_store_and_cache_only
- cached_serializer = build do |serializer|
- serializer._cache = Object
- serializer._cache_only = [:name]
- end
- assert cached_serializer.fragment_cached?
- end
-
- def test_fragment_cached_true_with_cache_store_and_cache_except
- cached_serializer = build do |serializer|
- serializer._cache = Object
- serializer._cache_except = [:content]
- end
- assert cached_serializer.fragment_cached?
- end
-
- def test_fragment_cached_false_with_cache_store_and_cache_except_and_cache_only
- cached_serializer = build do |serializer|
- serializer._cache = Object
- serializer._cache_except = [:content]
- serializer._cache_only = [:name]
- end
- refute cached_serializer.fragment_cached?
- end
-
- private
-
- def build
- serializer = Class.new(ActiveModel::Serializer)
- serializer._cache_key = nil
- serializer._cache_options = nil
- yield serializer if block_given?
- serializer_instance = serializer.new(Object)
- CachedSerializer.new(serializer_instance)
- end
- end
- end
-end
diff --git a/test/active_model_serializers/fragment_cache_test.rb b/test/active_model_serializers/fragment_cache_test.rb
deleted file mode 100644
index b44b9052..00000000
--- a/test/active_model_serializers/fragment_cache_test.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require 'test_helper'
-module ActiveModelSerializers
- class FragmentCacheTest < ActiveSupport::TestCase
- def setup
- super
- @spam = Spam::UnrelatedLink.new(id: 'spam-id-1')
- @author = Author.new(name: 'Joao M. D. Moura')
- @role = Role.new(name: 'Great Author', description: nil)
- @role.author = [@author]
- @role_serializer = RoleSerializer.new(@role)
- @spam_serializer = Spam::UnrelatedLinkSerializer.new(@spam)
- adapter = ActiveModelSerializers::Adapter.configured_adapter
- @role_hash = FragmentCache.new(adapter.new(@role_serializer), @role_serializer, {})
- @spam_hash = FragmentCache.new(adapter.new(@spam_serializer), @spam_serializer, {})
- end
-
- def test_fragment_fetch_with_virtual_attributes
- expected_result = {
- id: @role.id,
- description: @role.description,
- slug: "#{@role.name}-#{@role.id}",
- name: @role.name
- }
- assert_equal(@role_hash.fetch, expected_result)
- end
-
- def test_fragment_fetch_with_namespaced_object
- expected_result = {
- id: @spam.id
- }
- assert_equal(@spam_hash.fetch, expected_result)
- end
- end
-end
diff --git a/test/cache_test.rb b/test/cache_test.rb
index 283f35b8..57173d61 100644
--- a/test/cache_test.rb
+++ b/test/cache_test.rb
@@ -114,7 +114,7 @@ module ActiveModelSerializers
def test_error_is_raised_if_cache_key_is_not_defined_on_object_or_passed_as_cache_option
article = Article.new(title: 'Must Read')
- e = assert_raises ActiveModelSerializers::CachedSerializer::UndefinedCacheKey do
+ e = assert_raises ActiveModel::Serializer::UndefinedCacheKey do
render_object_with_cache(article)
end
assert_match(/ActiveModelSerializers::CacheTest::Article must define #cache_key, or the 'key:' option must be passed into 'CachedActiveModelSerializers_CacheTest_ArticleSerializer.cache'/, e.message)
@@ -252,11 +252,11 @@ module ActiveModelSerializers
attributes_serialization = serializable_alert.as_json
assert_equal expected_cached_attributes, alert.attributes
assert_equal alert.attributes, attributes_serialization
- attributes_cache_key = CachedSerializer.new(serializable_alert.adapter.serializer).cache_key(serializable_alert.adapter)
+ attributes_cache_key = serializable_alert.adapter.serializer.cache_key(serializable_alert.adapter)
assert_equal attributes_serialization, cache_store.fetch(attributes_cache_key)
serializable_alert = serializable(alert, serializer: AlertSerializer, adapter: :json_api)
- jsonapi_cache_key = CachedSerializer.new(serializable_alert.adapter.serializer).cache_key(serializable_alert.adapter)
+ jsonapi_cache_key = serializable_alert.adapter.serializer.cache_key(serializable_alert.adapter)
# Assert cache keys differ
refute_equal attributes_cache_key, jsonapi_cache_key
# Assert (cached) serializations differ
@@ -288,9 +288,9 @@ module ActiveModelSerializers
serializable = ActiveModelSerializers::SerializableResource.new([@comment, @comment])
include_tree = ActiveModel::Serializer::IncludeTree.from_include_args('*')
- actual = CachedSerializer.object_cache_keys(serializable.adapter.serializer, serializable.adapter, include_tree)
+ actual = ActiveModel::Serializer.object_cache_keys(serializable.adapter.serializer, serializable.adapter, include_tree)
- assert_equal actual.size, 3
+ assert_equal 3, actual.size
assert actual.any? { |key| key == "comment/1/#{serializable.adapter.cached_name}" }
assert actual.any? { |key| key =~ %r{post/post-\d+} }
assert actual.any? { |key| key =~ %r{author/author-\d+} }
@@ -365,12 +365,109 @@ module ActiveModelSerializers
assert called
end
+ def test_cached_false_without_cache_store
+ cached_serializer = build_cached_serializer do |serializer|
+ serializer._cache = nil
+ end
+ refute cached_serializer.class.cache_enabled?
+ end
+
+ def test_cached_true_with_cache_store_and_without_cache_only_and_cache_except
+ cached_serializer = build_cached_serializer do |serializer|
+ serializer._cache = Object
+ end
+ assert cached_serializer.class.cache_enabled?
+ end
+
+ def test_cached_false_with_cache_store_and_with_cache_only
+ cached_serializer = build_cached_serializer do |serializer|
+ serializer._cache = Object
+ serializer._cache_only = [:name]
+ end
+ refute cached_serializer.class.cache_enabled?
+ end
+
+ def test_cached_false_with_cache_store_and_with_cache_except
+ cached_serializer = build_cached_serializer do |serializer|
+ serializer._cache = Object
+ serializer._cache_except = [:content]
+ end
+ refute cached_serializer.class.cache_enabled?
+ end
+
+ def test_fragment_cached_false_without_cache_store
+ cached_serializer = build_cached_serializer do |serializer|
+ serializer._cache = nil
+ serializer._cache_only = [:name]
+ end
+ refute cached_serializer.class.fragment_cache_enabled?
+ end
+
+ def test_fragment_cached_true_with_cache_store_and_cache_only
+ cached_serializer = build_cached_serializer do |serializer|
+ serializer._cache = Object
+ serializer._cache_only = [:name]
+ end
+ assert cached_serializer.class.fragment_cache_enabled?
+ end
+
+ def test_fragment_cached_true_with_cache_store_and_cache_except
+ cached_serializer = build_cached_serializer do |serializer|
+ serializer._cache = Object
+ serializer._cache_except = [:content]
+ end
+ assert cached_serializer.class.fragment_cache_enabled?
+ end
+
+ def test_fragment_cached_false_with_cache_store_and_cache_except_and_cache_only
+ cached_serializer = build_cached_serializer do |serializer|
+ serializer._cache = Object
+ serializer._cache_except = [:content]
+ serializer._cache_only = [:name]
+ end
+ refute cached_serializer.class.fragment_cache_enabled?
+ end
+
+ def test_fragment_fetch_with_virtual_attributes
+ @author = Author.new(name: 'Joao M. D. Moura')
+ @role = Role.new(name: 'Great Author', description: nil)
+ @role.author = [@author]
+ @role_serializer = RoleSerializer.new(@role)
+ @role_hash = @role_serializer.fetch_fragment_cache(ActiveModelSerializers::Adapter.configured_adapter.new(@role_serializer))
+
+ expected_result = {
+ id: @role.id,
+ description: @role.description,
+ slug: "#{@role.name}-#{@role.id}",
+ name: @role.name
+ }
+ assert_equal(@role_hash, expected_result)
+ end
+
+ def test_fragment_fetch_with_namespaced_object
+ @spam = Spam::UnrelatedLink.new(id: 'spam-id-1')
+ @spam_serializer = Spam::UnrelatedLinkSerializer.new(@spam)
+ @spam_hash = @spam_serializer.fetch_fragment_cache(ActiveModelSerializers::Adapter.configured_adapter.new(@spam_serializer))
+ expected_result = {
+ id: @spam.id
+ }
+ assert_equal(@spam_hash, expected_result)
+ end
+
private
def cache_store
ActiveModelSerializers.config.cache_store
end
+ def build_cached_serializer
+ serializer = Class.new(ActiveModel::Serializer)
+ serializer._cache_key = nil
+ serializer._cache_options = nil
+ yield serializer if block_given?
+ serializer.new(Object)
+ end
+
def render_object_with_cache(obj, options = {})
@serializable_resource = serializable(obj, options)
@serializable_resource.serializable_hash
@@ -381,7 +478,7 @@ module ActiveModelSerializers
end
def cached_serialization(serializer)
- cache_key = CachedSerializer.new(serializer).cache_key(adapter)
+ cache_key = serializer.cache_key(adapter)
cache_store.fetch(cache_key)
end
end