forked from runtastic/active_model_serializers
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- The removed classes and modules were added back with deprecation warning and deprecation test were added for them. - One test was renamed because it contained `__`. - Some tests were refactored. - The ActiveModelSerializers::Deserialization module is now called Adapter instead of ActiveModelSerializers::Adapter. - The changelog was added for rails-api#1535
- Loading branch information
Yohan Robert
committed
Feb 28, 2016
1 parent
8a04005
commit e6fdeac
Showing
19 changed files
with
1,181 additions
and
51 deletions.
There are no files selected for viewing
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
module ActiveModel | ||
class Serializer | ||
module Adapter | ||
UnknownAdapterError = Class.new(ArgumentError) | ||
ADAPTER_MAP = {} | ||
private_constant :ADAPTER_MAP if defined?(private_constant) | ||
require 'active_model/serializer/adapter/fragment_cache' | ||
require 'active_model/serializer/adapter/cached_serializer' | ||
|
||
class << self # All methods are class functions | ||
def new(*args) | ||
fail ArgumentError, 'Adapters inherit from Adapter::Base.' \ | ||
"Adapter.new called with args: '#{args.inspect}', from" \ | ||
"'caller[0]'." | ||
end | ||
|
||
def create(resource, options = {}) | ||
warn "Calling deprecated ActiveModel::Serializer::Adater in #{caller[0..2].join(', ')}. Please use ActiveModelSerializers::Adapter" | ||
override = options.delete(:adapter) | ||
klass = override ? adapter_class(override) : ActiveModel::Serializer.adapter | ||
klass.new(resource, options) | ||
end | ||
|
||
# @see ActiveModel::Serializer::Adapter.lookup | ||
def adapter_class(adapter) | ||
warn "Calling deprecated ActiveModel::Serializer::Adater in #{caller[0..2].join(', ')}. Please use ActiveModelSerializers::Adapter" | ||
ActiveModel::Serializer::Adapter.lookup(adapter) | ||
end | ||
|
||
# @return Hash<adapter_name, adapter_class> | ||
def adapter_map | ||
warn "Calling deprecated ActiveModel::Serializer::Adater in #{caller[0..2].join(', ')}. Please use ActiveModelSerializers::Adapter" | ||
ADAPTER_MAP | ||
end | ||
|
||
# @return [Array<Symbol>] list of adapter names | ||
def adapters | ||
warn "Calling deprecated ActiveModel::Serializer::Adater in #{caller[0..2].join(', ')}. Please use ActiveModelSerializers::Adapter" | ||
adapter_map.keys.sort | ||
end | ||
|
||
# Adds an adapter 'klass' with 'name' to the 'adapter_map' | ||
# Names are stringified and underscored | ||
# @param name [Symbol, String, Class] name of the registered adapter | ||
# @param klass [Class] adapter class itself, optional if name is the class | ||
# @example | ||
# AMS::Adapter.register(:my_adapter, MyAdapter) | ||
# @note The registered name strips out 'ActiveModel::Serializer::Adapter::' | ||
# so that registering 'ActiveModel::Serializer::Adapter::Json' and | ||
# 'Json' will both register as 'json'. | ||
def register(name, klass = name) | ||
name = name.to_s.gsub(/\AActiveModel::Serializer::Adapter::/, ''.freeze).underscore | ||
unless %w(json_api json attributes null).include?(name) | ||
warn "Calling deprecated ActiveModel::Serializer::Adater in #{caller[0..2].join(', ')}. Please use ActiveModelSerializers::Adapter" | ||
end | ||
ADAPTER_MAP.update(name => klass) | ||
self | ||
end | ||
|
||
# @param adapter [String, Symbol, Class] name to fetch adapter by | ||
# @return [ActiveModel::Serializer::Adapter] subclass of Adapter | ||
# @raise [UnknownAdapterError] | ||
def lookup(adapter) | ||
warn "Calling deprecated ActiveModel::Serializer::Adater in #{caller[0..2].join(', ')}. Please use ActiveModelSerializers::Adapter" | ||
# 1. return if is a class | ||
return adapter if adapter.is_a?(Class) | ||
adapter_name = adapter.to_s.underscore | ||
# 2. return if registered | ||
adapter_map.fetch(adapter_name) do | ||
# 3. try to find adapter class from environment | ||
adapter_class = find_by_name(adapter_name) | ||
register(adapter_name, adapter_class) | ||
adapter_class | ||
end | ||
rescue NameError, ArgumentError => e | ||
failure_message = | ||
"NameError: #{e.message}. Unknown adapter: #{adapter.inspect}. Valid adapters are: #{adapters}" | ||
raise UnknownAdapterError, failure_message, e.backtrace | ||
end | ||
|
||
# @api private | ||
def find_by_name(adapter_name) | ||
adapter_name = adapter_name.to_s.classify.tr('API', 'Api') | ||
"ActiveModel::Serializer::Adapter::#{adapter_name}".safe_constantize || | ||
"ActiveModel::Serializer::Adapter::#{adapter_name.pluralize}".safe_constantize or # rubocop:disable Style/AndOr | ||
fail UnknownAdapterError | ||
end | ||
private :find_by_name | ||
end | ||
|
||
# Gotta be at the bottom to use the code above it :( | ||
require 'active_model/serializer/adapter/base' | ||
require 'active_model/serializer/adapter/null' | ||
require 'active_model/serializer/adapter/attributes' | ||
require 'active_model/serializer/adapter/json' | ||
require 'active_model/serializer/adapter/json_api' | ||
end | ||
end | ||
end |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
module ActiveModel | ||
class Serializer | ||
module Adapter | ||
class Attributes < Base | ||
def initialize(serializer, options = {}) | ||
warn 'Using ActiveModel::Serializer::Adater::Attributes is deprecated, please use the ActiveModelSerializers::Adapter::Attributes' | ||
super | ||
@include_tree = IncludeTree.from_include_args(options[:include] || '*') | ||
@cached_attributes = options[:cache_attributes] || {} | ||
end | ||
|
||
def serializable_hash(options = nil) | ||
options ||= {} | ||
|
||
if serializer.respond_to?(:each) | ||
serializable_hash_for_collection(options) | ||
else | ||
serializable_hash_for_single_resource(options) | ||
end | ||
end | ||
|
||
def fragment_cache(cached_hash, non_cached_hash) | ||
Json::FragmentCache.new.fragment_cache(cached_hash, non_cached_hash) | ||
end | ||
|
||
private | ||
|
||
def serializable_hash_for_collection(options) | ||
cache_attributes | ||
|
||
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, @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) { yield } | ||
end | ||
|
||
def serializable_hash_for_single_resource(options) | ||
resource = resource_object_for(options) | ||
relationships = resource_relationships(options) | ||
resource.merge!(relationships) | ||
end | ||
|
||
def resource_relationships(options) | ||
relationships = {} | ||
serializer.associations(@include_tree).each do |association| | ||
relationships[association.key] = relationship_value_for(association, options) | ||
end | ||
|
||
relationships | ||
end | ||
|
||
def relationship_value_for(association, options) | ||
return association.options[:virtual_value] if association.options[:virtual_value] | ||
return unless association.serializer && association.serializer.object | ||
|
||
opts = instance_options.merge(include: @include_tree[association.key]) | ||
Attributes.new(association.serializer, opts).serializable_hash(options) | ||
end | ||
|
||
# no-op: Attributes adapter does not include meta data, because it does not support root. | ||
def include_meta(json) | ||
json | ||
end | ||
|
||
def resource_object_for(options) | ||
cached_serializer = CachedSerializer.new(serializer) | ||
|
||
cached_attributes(cached_serializer) do | ||
cached_serializer.cache_check(self) do | ||
serializer.attributes(options[:fields]) | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
module ActiveModel | ||
class Serializer | ||
module Adapter | ||
class Base | ||
DEPRECATED_ADAPTERS = [ | ||
'ActiveModel::Serializer::Adapter::JsonApi', | ||
'ActiveModel::Serializer::Adapter::Attributes', | ||
'ActiveModel::Serializer::Adapter::Json', | ||
'ActiveModel::Serializer::Adapter::Null' | ||
] | ||
# Automatically register adapters when subclassing | ||
def self.inherited(subclass) | ||
unless DEPRECATED_ADAPTERS.include?(subclass.to_s) | ||
warn "Inheriting deprecated ActiveModel::Serializer::Adater::Base in #{caller[0..2].join(', ')}. Please use ActiveModelSerializers::Adapter" | ||
end | ||
ActiveModel::Serializer::Adapter.register(subclass) | ||
end | ||
|
||
attr_reader :serializer, :instance_options | ||
|
||
def initialize(serializer, options = {}) | ||
@serializer = serializer | ||
@instance_options = options | ||
end | ||
|
||
def serializable_hash(_options = nil) | ||
fail NotImplementedError, 'This is an abstract method. Should be implemented at the concrete adapter.' | ||
end | ||
|
||
def as_json(options = nil) | ||
hash = serializable_hash(options) | ||
include_meta(hash) | ||
hash | ||
end | ||
|
||
def fragment_cache(*_args) | ||
fail NotImplementedError, 'This is an abstract method. Should be implemented at the concrete adapter.' | ||
end | ||
|
||
def cache_check(serializer) | ||
CachedSerializer.new(serializer).cache_check(self) do | ||
yield | ||
end | ||
end | ||
|
||
private | ||
|
||
def meta | ||
instance_options.fetch(:meta, nil) | ||
end | ||
|
||
def meta_key | ||
instance_options.fetch(:meta_key, 'meta'.freeze) | ||
end | ||
|
||
def root | ||
serializer.json_key.to_sym if serializer.json_key | ||
end | ||
|
||
def include_meta(json) | ||
json[meta_key] = meta if meta | ||
json | ||
end | ||
end | ||
end | ||
end | ||
end |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
module ActiveModel | ||
class Serializer | ||
module 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 && (@klass._cache_only && !@klass._cache_except || !@klass._cache_only && @klass._cache_except) | ||
end | ||
|
||
def cache_key | ||
return @cache_key if defined?(@cache_key) | ||
|
||
parts = [] | ||
parts << object_cache_key | ||
parts << @klass._cache_digest unless @klass._cache_options && @klass._cache_options[:skip_digest] | ||
@cache_key = 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 | ||
|
||
# find all cache_key for the collection_serializer | ||
# @param collection_serializer | ||
# @param include_tree | ||
# @return [Array] all cache_key of collection_serializer | ||
def self.object_cache_keys(serializers, include_tree) | ||
cache_keys = [] | ||
|
||
serializers.each do |serializer| | ||
cache_keys << object_cache_key(serializer) | ||
|
||
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) | ||
end | ||
else | ||
cache_keys << object_cache_key(association.serializer) | ||
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) | ||
return unless serializer.present? && serializer.object.present? | ||
|
||
cached_serializer = new(serializer) | ||
cached_serializer.cached? ? cached_serializer.cache_key : nil | ||
end | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.