Distinguish options ivar from local; Extract latent Adapter::CachedSerializer

This commit is contained in:
Benjamin Fleischer
2015-09-16 22:12:13 -05:00
parent 3f0794bd39
commit 9d65f0adc5
10 changed files with 131 additions and 100 deletions

View File

@@ -10,6 +10,7 @@ module ActiveModel
autoload :JsonApi
autoload :Null
autoload :FlattenJson
autoload :CachedSerializer
def self.create(resource, options = {})
override = options.delete(:adapter)
@@ -80,11 +81,11 @@ module ActiveModel
ActiveModel::Serializer::Adapter.register(subclass.to_s.demodulize, subclass)
end
attr_reader :serializer
attr_reader :serializer, :instance_options
def initialize(serializer, options = {})
@serializer = serializer
@options = options
@instance_options = options
end
def serializable_hash(options = nil)
@@ -101,43 +102,12 @@ module ActiveModel
raise NotImplementedError, 'This is an abstract method. Should be implemented at the concrete adapter.'
end
private
def cache_check(serializer)
@cached_serializer = serializer
@klass = @cached_serializer.class
if is_cached?
@klass._cache.fetch(cache_key, @klass._cache_options) do
yield
end
elsif is_fragment_cached?
FragmentCache.new(self, @cached_serializer, @options).fetch
else
CachedSerializer.new(serializer).cache_check(self) do
yield
end
end
def is_cached?
@klass._cache && !@klass._cache_only && !@klass._cache_except
end
def is_fragment_cached?
@klass._cache_only && !@klass._cache_except || !@klass._cache_only && @klass._cache_except
end
def cache_key
parts = []
parts << object_cache_key
parts << @klass._cache_digest unless @klass._cache_options && @klass._cache_options[:skip_digest]
parts.join('/')
end
def object_cache_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)
(@klass._cache_key) ? "#{@klass._cache_key}/#{@cached_serializer.object.id}-#{object_time_safe}" : @cached_serializer.object.cache_key
end
def meta
serializer.meta if serializer.respond_to?(:meta)
end

View File

@@ -0,0 +1,45 @@
module ActiveModel
class Serializer
class Adapter
class CachedSerializer
def initialize(serializer)
@cached_serializer = serializer
@klass = @cached_serializer.class
end
def cache_check(adapter_instance)
if cached?
@klass._cache.fetch(cache_key, @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 && !@klass._cache_only && !@klass._cache_except
end
def fragment_cached?
@klass._cache_only && !@klass._cache_except || !@klass._cache_only && @klass._cache_except
end
def cache_key
parts = []
parts << object_cache_key
parts << @klass._cache_digest unless @klass._cache_options && @klass._cache_options[:skip_digest]
parts.join('/')
end
def object_cache_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)
(@klass._cache_key) ? "#{@klass._cache_key}/#{@cached_serializer.object.id}-#{object_time_safe}" : @cached_serializer.object.cache_key
end
end
end
end
end

View File

@@ -2,7 +2,7 @@ class ActiveModel::Serializer::Adapter::FragmentCache
attr_reader :serializer
def initialize(adapter, serializer, options)
@options = options
@instance_options = options
@adapter = adapter
@serializer = serializer
end
@@ -16,19 +16,23 @@ class ActiveModel::Serializer::Adapter::FragmentCache
cached_serializer = serializers[:cached].constantize.new(serializer.object)
non_cached_serializer = serializers[:non_cached].constantize.new(serializer.object)
cached_adapter = @adapter.class.new(cached_serializer, @options)
non_cached_adapter = @adapter.class.new(non_cached_serializer, @options)
cached_adapter = adapter.class.new(cached_serializer, instance_options)
non_cached_adapter = adapter.class.new(non_cached_serializer, instance_options)
# Get serializable hash from both
cached_hash = cached_adapter.serializable_hash
non_cached_hash = non_cached_adapter.serializable_hash
# Merge both results
@adapter.fragment_cache(cached_hash, non_cached_hash)
adapter.fragment_cache(cached_hash, non_cached_hash)
end
private
ActiveModelSerializers.silence_warnings do
attr_reader :instance_options, :adapter
end
def cached_attributes(klass, serializers)
attributes = serializer.class._attributes
cached_attributes = (klass._cache_only) ? klass._cache_only : attributes.reject { |attr| klass._cache_except.include?(attr) }

View File

@@ -15,13 +15,13 @@ class ActiveModel::Serializer::Adapter::Json < ActiveModel::Serializer::Adapter
serializer.associations.each do |association|
serializer = association.serializer
opts = association.options
association_options = association.options
if serializer.respond_to?(:each)
array_serializer = serializer
hash[association.key] = array_serializer.map do |item|
cache_check(item) do
item.attributes(opts)
item.attributes(association_options)
end
end
else
@@ -30,8 +30,8 @@ class ActiveModel::Serializer::Adapter::Json < ActiveModel::Serializer::Adapter
cache_check(serializer) do
serializer.attributes(options)
end
elsif opts[:virtual_value]
opts[:virtual_value]
elsif association_options[:virtual_value]
association_options[:virtual_value]
end
end
end

View File

@@ -5,7 +5,7 @@ class ActiveModel::Serializer::Adapter::JsonApi < ActiveModel::Serializer::Adapt
def initialize(serializer, options = {})
super
@included = ActiveModel::Serializer::Utils.include_args_to_hash(@options[:include])
@included = ActiveModel::Serializer::Utils.include_args_to_hash(instance_options[:include])
fields = options.delete(:fields)
if fields
@fieldset = ActiveModel::Serializer::Fieldset.new(fields, serializer.json_key)
@@ -24,16 +24,20 @@ class ActiveModel::Serializer::Adapter::JsonApi < ActiveModel::Serializer::Adapt
end
def fragment_cache(cached_hash, non_cached_hash)
root = false if @options.include?(:include)
root = false if instance_options.include?(:include)
ActiveModel::Serializer::Adapter::JsonApi::FragmentCache.new.fragment_cache(root, cached_hash, non_cached_hash)
end
private
ActiveModel.silence_warnings do
attr_reader :included, :fieldset
end
def serializable_hash_for_collection(serializer, options)
hash = { data: [] }
serializer.each do |s|
result = self.class.new(s, @options.merge(fieldset: @fieldset)).serializable_hash(options)
result = self.class.new(s, instance_options.merge(fieldset: fieldset)).serializable_hash(options)
hash[:data] << result[:data]
if result[:included]
@@ -85,7 +89,7 @@ class ActiveModel::Serializer::Adapter::JsonApi < ActiveModel::Serializer::Adapt
end
def resource_object_for(serializer, options = {})
options[:fields] = @fieldset && @fieldset.fields_for(serializer)
options[:fields] = fieldset && fieldset.fields_for(serializer)
cache_check(serializer) do
result = resource_identifier_for(serializer)
@@ -120,12 +124,10 @@ class ActiveModel::Serializer::Adapter::JsonApi < ActiveModel::Serializer::Adapt
end
def included_for(serializer)
included = @included.flat_map do |inc|
included.flat_map { |inc|
association = serializer.associations.find { |assoc| assoc.key == inc.first }
_included_for(association.serializer, inc.second) if association
end
included.uniq
}.uniq
end
def _included_for(serializer, includes)
@@ -134,7 +136,7 @@ class ActiveModel::Serializer::Adapter::JsonApi < ActiveModel::Serializer::Adapt
else
return [] unless serializer && serializer.object
primary_data = primary_data_for(serializer, @options)
primary_data = primary_data_for(serializer, instance_options)
relationships = relationships_for(serializer)
primary_data[:relationships] = relationships if relationships.any?

View File

@@ -26,7 +26,7 @@ module ActiveModel
end
def json_key
key = root || @serializers.first.try(:json_key) || object.try(:name).try(:underscore)
key = root || serializers.first.try(:json_key) || object.try(:name).try(:underscore)
key.try(:pluralize)
end
@@ -35,6 +35,12 @@ module ActiveModel
object.respond_to?(:total_pages) &&
object.respond_to?(:size)
end
private # rubocop:disable Lint/UselessAccessModifier
ActiveModelSerializers.silence_warnings do
attr_reader :serializers
end
end
end
end

View File

@@ -88,7 +88,7 @@ module ActiveModel
Enumerator.new do |y|
self.class._reflections.each do |reflection|
y.yield reflection.build_association(self, options)
y.yield reflection.build_association(self, instance_options)
end
end
end

View File

@@ -26,7 +26,7 @@ module ActiveModel
raw_fields.inject({}) { |h, (k, v)| h[k.to_sym] = v.map(&:to_sym); h }
elsif raw_fields.is_a?(Array)
if root.nil?
raise ArgumentError, 'The root argument must be specified if the fields argument is an array.'
raise ArgumentError, 'The root argument must be specified if the fields argument is an array.'.freeze
end
hash = {}
hash[root.to_sym] = raw_fields.map(&:to_sym)