mirror of
https://github.com/ditkrg/active_model_serializers.git
synced 2026-01-22 22:06:50 +00:00
Merge pull request #1535 from bf4/domitian-move-namespace-of-adapter-to-active-model-serializers
Moved the adapter and adapter folder to active_model_serializers folder and changed the module namespace
This commit is contained in:
commit
8a040052af
@ -222,7 +222,6 @@ Style/TrailingBlankLines:
|
||||
- 'test/adapter/null_test.rb'
|
||||
- 'test/serializers/cache_test.rb'
|
||||
- 'test/serializers/fieldset_test.rb'
|
||||
- 'test/support/stream_capture.rb'
|
||||
|
||||
# Offense count: 5
|
||||
# Cop supports --auto-correct.
|
||||
|
||||
@ -12,7 +12,9 @@
|
||||
- [](http://www.rubydoc.info/github/rails-api/active_model_serializers/v0.10.0.rc4)
|
||||
- [Guides](docs)
|
||||
- [0.9 (0-9-stable) Documentation](https://github.com/rails-api/active_model_serializers/tree/0-9-stable)
|
||||
- [](http://www.rubydoc.info/github/rails-api/active_model_serializers/0-9-stable)
|
||||
- [0.8 (0-8-stable) Documentation](https://github.com/rails-api/active_model_serializers/tree/0-8-stable)
|
||||
- [](http://www.rubydoc.info/github/rails-api/active_model_serializers/0-8-stable)
|
||||
|
||||
## About
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ It should be set only once, preferably at initialization.
|
||||
For example:
|
||||
|
||||
```ruby
|
||||
ActiveModelSerializers.config.adapter = ActiveModel::Serializer::Adapter::JsonApi
|
||||
ActiveModelSerializers.config.adapter = ActiveModelSerializers::Adapter::JsonApi
|
||||
```
|
||||
|
||||
or
|
||||
@ -117,46 +117,46 @@ The default adapter can be configured, as above, to use any class given to it.
|
||||
|
||||
An adapter may also be specified, e.g. when rendering, as a class or as a symbol.
|
||||
If a symbol, then the adapter must be, e.g. `:great_example`,
|
||||
`ActiveModel::Serializer::Adapter::GreatExample`, or registered.
|
||||
`ActiveModelSerializers::Adapter::GreatExample`, or registered.
|
||||
|
||||
There are two ways to register an adapter:
|
||||
|
||||
1) The simplest, is to subclass `ActiveModel::Serializer::Adapter::Base`, e.g. the below will
|
||||
1) The simplest, is to subclass `ActiveModelSerializers::Adapter::Base`, e.g. the below will
|
||||
register the `Example::UsefulAdapter` as `"example/useful_adapter"`.
|
||||
|
||||
```ruby
|
||||
module Example
|
||||
class UsefulAdapter < ActiveModel::Serializer::Adapter::Base
|
||||
class UsefulAdapter < ActiveModelSerializers::Adapter::Base
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
You'll notice that the name it registers is the underscored namespace and class.
|
||||
|
||||
Under the covers, when the `ActiveModel::Serializer::Adapter::Base` is subclassed, it registers
|
||||
Under the covers, when the `ActiveModelSerializers::Adapter::Base` is subclassed, it registers
|
||||
the subclass as `register("example/useful_adapter", Example::UsefulAdapter)`
|
||||
|
||||
2) Any class can be registered as an adapter by calling `register` directly on the
|
||||
`ActiveModel::Serializer::Adapter` class. e.g., the below registers `MyAdapter` as
|
||||
`ActiveModelSerializers::Adapter` class. e.g., the below registers `MyAdapter` as
|
||||
`:special_adapter`.
|
||||
|
||||
```ruby
|
||||
class MyAdapter; end
|
||||
ActiveModel::Serializer::Adapter.register(:special_adapter, MyAdapter)
|
||||
ActiveModelSerializers::Adapter.register(:special_adapter, MyAdapter)
|
||||
```
|
||||
|
||||
### Looking up an adapter
|
||||
|
||||
| Method | Return value |
|
||||
| :------------ |:---------------|
|
||||
| `ActiveModel::Serializer::Adapter.adapter_map` | A Hash of all known adapters `{ adapter_name => adapter_class }` |
|
||||
| `ActiveModel::Serializer::Adapter.adapters` | A (sorted) Array of all known `adapter_names` |
|
||||
| `ActiveModel::Serializer::Adapter.lookup(name_or_klass)` | The `adapter_class`, else raises an `ActiveModel::Serializer::Adapter::UnknownAdapter` error |
|
||||
| `ActiveModel::Serializer::Adapter.adapter_class(adapter)` | Delegates to `ActiveModel::Serializer::Adapter.lookup(adapter)` |
|
||||
| `ActiveModel::Serializer.adapter` | A convenience method for `ActiveModel::Serializer::Adapter.lookup(config.adapter)` |
|
||||
| `ActiveModelSerializers::Adapter.adapter_map` | A Hash of all known adapters `{ adapter_name => adapter_class }` |
|
||||
| `ActiveModelSerializers::Adapter.adapters` | A (sorted) Array of all known `adapter_names` |
|
||||
| `ActiveModelSerializers::Adapter.lookup(name_or_klass)` | The `adapter_class`, else raises an `ActiveModelSerializers::Adapter::UnknownAdapter` error |
|
||||
| `ActiveModelSerializers::Adapter.adapter_class(adapter)` | Delegates to `ActiveModelSerializers::Adapter.lookup(adapter)` |
|
||||
| `ActiveModelSerializers::Adapter.configured_adapter` | A convenience method for `ActiveModelSerializers::Adapter.lookup(config.adapter)` |
|
||||
|
||||
The registered adapter name is always a String, but may be looked up as a Symbol or String.
|
||||
Helpfully, the Symbol or String is underscored, so that `get(:my_adapter)` and `get("MyAdapter")`
|
||||
may both be used.
|
||||
|
||||
For more information, see [the Adapter class on GitHub](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model/serializer/adapter.rb)
|
||||
For more information, see [the Adapter class on GitHub](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model_serializers/adapter.rb)
|
||||
|
||||
@ -17,7 +17,7 @@ Payload (example):
|
||||
```ruby
|
||||
{
|
||||
serializer: PostSerializer,
|
||||
adapter: ActiveModel::Serializer::Adapter::Attributes
|
||||
adapter: ActiveModelSerializers::Adapter::Attributes
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@ -70,7 +70,7 @@ at the first moment.
|
||||
## Renaming of class and modules
|
||||
|
||||
When moving some content to the new namespace we can find some names that does
|
||||
not make much sense like `ActiveModelSerializers::Serializer::Adapter::JsonApi`.
|
||||
not make much sense like `ActiveModel::Serializer::Adapter::JsonApi`.
|
||||
Discussion of renaming existing classes / modules and JsonApi objects will
|
||||
happen in separate pull requests, and issues, and in the google doc
|
||||
https://docs.google.com/document/d/1rcrJr0sVcazY2Opd_6Kmv1iIwuHbI84s1P_NzFn-05c/edit?usp=sharing
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
require 'set'
|
||||
require 'active_model_serializers/adapter'
|
||||
module ActiveModel
|
||||
class SerializableResource
|
||||
ADAPTER_OPTION_KEYS = Set.new([:include, :fields, :adapter, :meta, :meta_key, :links])
|
||||
@ -30,7 +31,7 @@ module ActiveModel
|
||||
end
|
||||
|
||||
def adapter
|
||||
@adapter ||= ActiveModel::Serializer::Adapter.create(serializer_instance, adapter_opts)
|
||||
@adapter ||= ActiveModelSerializers::Adapter.create(serializer_instance, adapter_opts)
|
||||
end
|
||||
alias_method :adapter_instance, :adapter
|
||||
|
||||
|
||||
@ -23,7 +23,6 @@ module ActiveModel
|
||||
include Links
|
||||
include Meta
|
||||
include Type
|
||||
require 'active_model/serializer/adapter'
|
||||
|
||||
# @param resource [ActiveRecord::Base, ActiveModelSerializers::Model]
|
||||
# @return [ActiveModel::Serializer]
|
||||
@ -42,9 +41,11 @@ module ActiveModel
|
||||
end
|
||||
end
|
||||
|
||||
# @see ActiveModel::Serializer::Adapter.lookup
|
||||
# @see ActiveModelSerializers::Adapter.lookup
|
||||
# Deprecated
|
||||
def self.adapter
|
||||
ActiveModel::Serializer::Adapter.lookup(config.adapter)
|
||||
warn 'Calling adapter method in Serializer, please use the ActiveModelSerializers::configured_adapter'
|
||||
ActiveModelSerializers::Adapter.lookup(config.adapter)
|
||||
end
|
||||
|
||||
# @api private
|
||||
|
||||
@ -1,91 +0,0 @@
|
||||
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 = {})
|
||||
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)
|
||||
ActiveModel::Serializer::Adapter.lookup(adapter)
|
||||
end
|
||||
|
||||
# @return Hash<adapter_name, adapter_class>
|
||||
def adapter_map
|
||||
ADAPTER_MAP
|
||||
end
|
||||
|
||||
# @return [Array<Symbol>] list of adapter names
|
||||
def adapters
|
||||
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)
|
||||
adapter_map.update(name.underscore => 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)
|
||||
# 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
|
||||
@ -1,100 +0,0 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class Attributes < Base
|
||||
def initialize(serializer, options = {})
|
||||
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
|
||||
@ -1,58 +0,0 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class Base
|
||||
# Automatically register adapters when subclassing
|
||||
def self.inherited(subclass)
|
||||
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
|
||||
@ -1,79 +0,0 @@
|
||||
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
|
||||
@ -1,115 +0,0 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class FragmentCache
|
||||
attr_reader :serializer
|
||||
|
||||
def initialize(adapter, serializer, options)
|
||||
@instance_options = options
|
||||
@adapter = adapter
|
||||
@serializer = serializer
|
||||
end
|
||||
|
||||
# TODO: Use Serializable::Resource
|
||||
# TODO: call +constantize+ less
|
||||
# 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
|
||||
klass = serializer.class
|
||||
# It will split the serializer into two, one that will be cached and one that will not
|
||||
serializers = fragment_serializer(serializer.object.class.name, klass)
|
||||
|
||||
# Instantiate both serializers
|
||||
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, 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)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
attr_reader :instance_options, :adapter
|
||||
|
||||
private
|
||||
|
||||
# Given a serializer class and 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 cached_attributes(klass, serializers)
|
||||
attributes = serializer.class._attributes
|
||||
cached_attributes = (klass._cache_only) ? klass._cache_only : attributes.reject { |attr| klass._cache_except.include?(attr) }
|
||||
non_cached_attributes = attributes - cached_attributes
|
||||
|
||||
cached_attributes.each do |attribute|
|
||||
options = serializer.class._attributes_keys[attribute]
|
||||
options ||= {}
|
||||
# Add cached attributes to cached Serializer
|
||||
serializers[:cached].constantize.attribute(attribute, options)
|
||||
end
|
||||
|
||||
non_cached_attributes.each do |attribute|
|
||||
options = serializer.class._attributes_keys[attribute]
|
||||
options ||= {}
|
||||
# Add non-cached attributes to non-cached Serializer
|
||||
serializers[:non_cached].constantize.attribute(attribute, options)
|
||||
end
|
||||
end
|
||||
|
||||
# Given a resource name and its serializer's class
|
||||
# 1. Dyanmically creates a CachedSerializer and NonCachedSerializer
|
||||
# for a given class 'name'
|
||||
# 2. Call
|
||||
# CachedSerializer.cache(serializer._cache_options)
|
||||
# CachedSerializer.fragmented(serializer)
|
||||
# NontCachedSerializer.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 <tt>User::Admin</tt>
|
||||
# creates the Serializer classes (if they don't exist).
|
||||
# User_AdminCachedSerializer
|
||||
# User_AdminNOnCachedSerializer
|
||||
#
|
||||
def fragment_serializer(name, klass)
|
||||
cached = "#{to_valid_const_name(name)}CachedSerializer"
|
||||
non_cached = "#{to_valid_const_name(name)}NonCachedSerializer"
|
||||
|
||||
Object.const_set cached, Class.new(ActiveModel::Serializer) unless Object.const_defined?(cached)
|
||||
Object.const_set non_cached, Class.new(ActiveModel::Serializer) unless Object.const_defined?(non_cached)
|
||||
|
||||
klass._cache_options ||= {}
|
||||
klass._cache_options[:key] = klass._cache_key if klass._cache_key
|
||||
|
||||
cached.constantize.cache(klass._cache_options)
|
||||
|
||||
# Preserve the type setting in the cached/non-cached serializer classes
|
||||
cached.constantize.type(klass._type)
|
||||
non_cached.constantize.type(klass._type)
|
||||
|
||||
cached.constantize.fragmented(serializer)
|
||||
non_cached.constantize.fragmented(serializer)
|
||||
|
||||
serializers = { cached: cached, non_cached: non_cached }
|
||||
cached_attributes(klass, serializers)
|
||||
serializers
|
||||
end
|
||||
|
||||
def to_valid_const_name(name)
|
||||
name.gsub('::', '_')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,21 +0,0 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class Json < Base
|
||||
extend ActiveSupport::Autoload
|
||||
autoload :FragmentCache
|
||||
|
||||
def serializable_hash(options = nil)
|
||||
options ||= {}
|
||||
{ root => Attributes.new(serializer, instance_options).serializable_hash(options) }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fragment_cache(cached_hash, non_cached_hash)
|
||||
ActiveModel::Serializer::Adapter::Json::FragmentCache.new.fragment_cache(cached_hash, non_cached_hash)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,13 +0,0 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class Json
|
||||
class FragmentCache
|
||||
def fragment_cache(cached_hash, non_cached_hash)
|
||||
non_cached_hash.merge cached_hash
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,188 +0,0 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class JsonApi < Base
|
||||
extend ActiveSupport::Autoload
|
||||
autoload :PaginationLinks
|
||||
autoload :FragmentCache
|
||||
autoload :Link
|
||||
autoload :Meta
|
||||
autoload :Deserialization
|
||||
require 'active_model/serializer/adapter/json_api/api_objects'
|
||||
|
||||
# TODO: if we like this abstraction and other API objects to it,
|
||||
# then extract to its own file and require it.
|
||||
module ApiObjects
|
||||
module JsonApi
|
||||
ActiveModelSerializers.config.jsonapi_version = '1.0'
|
||||
ActiveModelSerializers.config.jsonapi_toplevel_meta = {}
|
||||
# Make JSON API top-level jsonapi member opt-in
|
||||
# ref: http://jsonapi.org/format/#document-top-level
|
||||
ActiveModelSerializers.config.jsonapi_include_toplevel_object = false
|
||||
|
||||
module_function
|
||||
|
||||
def add!(hash)
|
||||
hash.merge!(object) if include_object?
|
||||
end
|
||||
|
||||
def include_object?
|
||||
ActiveModelSerializers.config.jsonapi_include_toplevel_object
|
||||
end
|
||||
|
||||
# TODO: see if we can cache this
|
||||
def object
|
||||
object = {
|
||||
jsonapi: {
|
||||
version: ActiveModelSerializers.config.jsonapi_version,
|
||||
meta: ActiveModelSerializers.config.jsonapi_toplevel_meta
|
||||
}
|
||||
}
|
||||
object[:jsonapi].reject! { |_, v| v.blank? }
|
||||
|
||||
object
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(serializer, options = {})
|
||||
super
|
||||
@include_tree = IncludeTree.from_include_args(options[:include])
|
||||
@fieldset = options[:fieldset] || ActiveModel::Serializer::Fieldset.new(options.delete(:fields))
|
||||
end
|
||||
|
||||
def serializable_hash(options = nil)
|
||||
options ||= {}
|
||||
|
||||
is_collection = serializer.respond_to?(:each)
|
||||
serializers = is_collection ? serializer : [serializer]
|
||||
primary_data, included = resource_objects_for(serializers)
|
||||
|
||||
hash = {}
|
||||
hash[:data] = is_collection ? primary_data : primary_data[0]
|
||||
hash[:included] = included if included.any?
|
||||
|
||||
ApiObjects::JsonApi.add!(hash)
|
||||
|
||||
if instance_options[:links]
|
||||
hash[:links] ||= {}
|
||||
hash[:links].update(instance_options[:links])
|
||||
end
|
||||
|
||||
if is_collection && serializer.paginated?
|
||||
hash[:links] ||= {}
|
||||
hash[:links].update(pagination_links_for(serializer, options))
|
||||
end
|
||||
|
||||
hash
|
||||
end
|
||||
|
||||
def fragment_cache(cached_hash, non_cached_hash)
|
||||
root = false if instance_options.include?(:include)
|
||||
ActiveModel::Serializer::Adapter::JsonApi::FragmentCache.new.fragment_cache(root, cached_hash, non_cached_hash)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
attr_reader :fieldset
|
||||
|
||||
private
|
||||
|
||||
def resource_objects_for(serializers)
|
||||
@primary = []
|
||||
@included = []
|
||||
@resource_identifiers = Set.new
|
||||
serializers.each { |serializer| process_resource(serializer, true) }
|
||||
serializers.each { |serializer| process_relationships(serializer, @include_tree) }
|
||||
|
||||
[@primary, @included]
|
||||
end
|
||||
|
||||
def process_resource(serializer, primary)
|
||||
resource_identifier = ApiObjects::ResourceIdentifier.new(serializer).as_json
|
||||
return false unless @resource_identifiers.add?(resource_identifier)
|
||||
|
||||
resource_object = resource_object_for(serializer)
|
||||
if primary
|
||||
@primary << resource_object
|
||||
else
|
||||
@included << resource_object
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def process_relationships(serializer, include_tree)
|
||||
serializer.associations(include_tree).each do |association|
|
||||
process_relationship(association.serializer, include_tree[association.key])
|
||||
end
|
||||
end
|
||||
|
||||
def process_relationship(serializer, include_tree)
|
||||
if serializer.respond_to?(:each)
|
||||
serializer.each { |s| process_relationship(s, include_tree) }
|
||||
return
|
||||
end
|
||||
return unless serializer && serializer.object
|
||||
return unless process_resource(serializer, false)
|
||||
|
||||
process_relationships(serializer, include_tree)
|
||||
end
|
||||
|
||||
def attributes_for(serializer, fields)
|
||||
serializer.attributes(fields).except(:id)
|
||||
end
|
||||
|
||||
def resource_object_for(serializer)
|
||||
resource_object = cache_check(serializer) do
|
||||
resource_object = ApiObjects::ResourceIdentifier.new(serializer).as_json
|
||||
|
||||
requested_fields = fieldset && fieldset.fields_for(resource_object[:type])
|
||||
attributes = attributes_for(serializer, requested_fields)
|
||||
resource_object[:attributes] = attributes if attributes.any?
|
||||
resource_object
|
||||
end
|
||||
|
||||
requested_associations = fieldset.fields_for(resource_object[:type]) || '*'
|
||||
relationships = relationships_for(serializer, requested_associations)
|
||||
resource_object[:relationships] = relationships if relationships.any?
|
||||
|
||||
links = links_for(serializer)
|
||||
resource_object[:links] = links if links.any?
|
||||
|
||||
meta = meta_for(serializer)
|
||||
resource_object[:meta] = meta unless meta.nil?
|
||||
|
||||
resource_object
|
||||
end
|
||||
|
||||
def relationships_for(serializer, requested_associations)
|
||||
include_tree = IncludeTree.from_include_args(requested_associations)
|
||||
serializer.associations(include_tree).each_with_object({}) do |association, hash|
|
||||
hash[association.key] = ApiObjects::Relationship.new(
|
||||
serializer,
|
||||
association.serializer,
|
||||
association.options,
|
||||
association.links,
|
||||
association.meta
|
||||
).as_json
|
||||
end
|
||||
end
|
||||
|
||||
def links_for(serializer)
|
||||
serializer._links.each_with_object({}) do |(name, value), hash|
|
||||
hash[name] = Link.new(serializer, value).as_json
|
||||
end
|
||||
end
|
||||
|
||||
def pagination_links_for(serializer, options)
|
||||
JsonApi::PaginationLinks.new(serializer.object, options[:serialization_context]).serializable_hash(options)
|
||||
end
|
||||
|
||||
def meta_for(serializer)
|
||||
Meta.new(serializer).as_json
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -11,7 +11,7 @@ module ActiveModel
|
||||
@options = options
|
||||
@data = data_for(serializer, options)
|
||||
@links = links.each_with_object({}) do |(key, value), hash|
|
||||
hash[key] = Link.new(parent_serializer, value).as_json
|
||||
hash[key] = ActiveModelSerializers::Adapter::JsonApi::Link.new(parent_serializer, value).as_json
|
||||
end
|
||||
@meta = meta.respond_to?(:call) ? parent_serializer.instance_eval(&meta) : meta
|
||||
end
|
||||
|
||||
@ -1,207 +0,0 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class JsonApi
|
||||
# NOTE(Experimental):
|
||||
# This is an experimental feature. Both the interface and internals could be subject
|
||||
# to changes.
|
||||
module Deserialization
|
||||
InvalidDocument = Class.new(ArgumentError)
|
||||
|
||||
module_function
|
||||
|
||||
# Transform a JSON API document, containing a single data object,
|
||||
# into a hash that is ready for ActiveRecord::Base.new() and such.
|
||||
# Raises InvalidDocument if the payload is not properly formatted.
|
||||
#
|
||||
# @param [Hash|ActionController::Parameters] document
|
||||
# @param [Hash] options
|
||||
# only: Array of symbols of whitelisted fields.
|
||||
# except: Array of symbols of blacklisted fields.
|
||||
# keys: Hash of translated keys (e.g. :author => :user).
|
||||
# polymorphic: Array of symbols of polymorphic fields.
|
||||
# @return [Hash]
|
||||
#
|
||||
# @example
|
||||
# document = {
|
||||
# data: {
|
||||
# id: 1,
|
||||
# type: 'post',
|
||||
# attributes: {
|
||||
# title: 'Title 1',
|
||||
# date: '2015-12-20'
|
||||
# },
|
||||
# associations: {
|
||||
# author: {
|
||||
# data: {
|
||||
# type: 'user',
|
||||
# id: 2
|
||||
# }
|
||||
# },
|
||||
# second_author: {
|
||||
# data: nil
|
||||
# },
|
||||
# comments: {
|
||||
# data: [{
|
||||
# type: 'comment',
|
||||
# id: 3
|
||||
# },{
|
||||
# type: 'comment',
|
||||
# id: 4
|
||||
# }]
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# parse(document) #=>
|
||||
# # {
|
||||
# # title: 'Title 1',
|
||||
# # date: '2015-12-20',
|
||||
# # author_id: 2,
|
||||
# # second_author_id: nil
|
||||
# # comment_ids: [3, 4]
|
||||
# # }
|
||||
#
|
||||
# parse(document, only: [:title, :date, :author],
|
||||
# keys: { date: :published_at },
|
||||
# polymorphic: [:author]) #=>
|
||||
# # {
|
||||
# # title: 'Title 1',
|
||||
# # published_at: '2015-12-20',
|
||||
# # author_id: '2',
|
||||
# # author_type: 'people'
|
||||
# # }
|
||||
#
|
||||
def parse!(document, options = {})
|
||||
parse(document, options) do |invalid_payload, reason|
|
||||
fail InvalidDocument, "Invalid payload (#{reason}): #{invalid_payload}"
|
||||
end
|
||||
end
|
||||
|
||||
# Same as parse!, but returns an empty hash instead of raising InvalidDocument
|
||||
# on invalid payloads.
|
||||
def parse(document, options = {})
|
||||
document = document.dup.permit!.to_h if document.is_a?(ActionController::Parameters)
|
||||
|
||||
validate_payload(document) do |invalid_document, reason|
|
||||
yield invalid_document, reason if block_given?
|
||||
return {}
|
||||
end
|
||||
|
||||
primary_data = document['data']
|
||||
attributes = primary_data['attributes'] || {}
|
||||
attributes['id'] = primary_data['id'] if primary_data['id']
|
||||
relationships = primary_data['relationships'] || {}
|
||||
|
||||
filter_fields(attributes, options)
|
||||
filter_fields(relationships, options)
|
||||
|
||||
hash = {}
|
||||
hash.merge!(parse_attributes(attributes, options))
|
||||
hash.merge!(parse_relationships(relationships, options))
|
||||
|
||||
hash
|
||||
end
|
||||
|
||||
# Checks whether a payload is compliant with the JSON API spec.
|
||||
#
|
||||
# @api private
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
def validate_payload(payload)
|
||||
unless payload.is_a?(Hash)
|
||||
yield payload, 'Expected hash'
|
||||
return
|
||||
end
|
||||
|
||||
primary_data = payload['data']
|
||||
unless primary_data.is_a?(Hash)
|
||||
yield payload, { data: 'Expected hash' }
|
||||
return
|
||||
end
|
||||
|
||||
attributes = primary_data['attributes'] || {}
|
||||
unless attributes.is_a?(Hash)
|
||||
yield payload, { data: { attributes: 'Expected hash or nil' } }
|
||||
return
|
||||
end
|
||||
|
||||
relationships = primary_data['relationships'] || {}
|
||||
unless relationships.is_a?(Hash)
|
||||
yield payload, { data: { relationships: 'Expected hash or nil' } }
|
||||
return
|
||||
end
|
||||
|
||||
relationships.each do |(key, value)|
|
||||
unless value.is_a?(Hash) && value.key?('data')
|
||||
yield payload, { data: { relationships: { key => 'Expected hash with :data key' } } }
|
||||
end
|
||||
end
|
||||
end
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
|
||||
# @api private
|
||||
def filter_fields(fields, options)
|
||||
if (only = options[:only])
|
||||
fields.slice!(*Array(only).map(&:to_s))
|
||||
elsif (except = options[:except])
|
||||
fields.except!(*Array(except).map(&:to_s))
|
||||
end
|
||||
end
|
||||
|
||||
# @api private
|
||||
def field_key(field, options)
|
||||
(options[:keys] || {}).fetch(field.to_sym, field).to_sym
|
||||
end
|
||||
|
||||
# @api private
|
||||
def parse_attributes(attributes, options)
|
||||
attributes
|
||||
.map { |(k, v)| { field_key(k, options) => v } }
|
||||
.reduce({}, :merge)
|
||||
end
|
||||
|
||||
# Given an association name, and a relationship data attribute, build a hash
|
||||
# mapping the corresponding ActiveRecord attribute to the corresponding value.
|
||||
#
|
||||
# @example
|
||||
# parse_relationship(:comments, [{ 'id' => '1', 'type' => 'comments' },
|
||||
# { 'id' => '2', 'type' => 'comments' }],
|
||||
# {})
|
||||
# # => { :comment_ids => ['1', '2'] }
|
||||
# parse_relationship(:author, { 'id' => '1', 'type' => 'users' }, {})
|
||||
# # => { :author_id => '1' }
|
||||
# parse_relationship(:author, nil, {})
|
||||
# # => { :author_id => nil }
|
||||
# @param [Symbol] assoc_name
|
||||
# @param [Hash] assoc_data
|
||||
# @param [Hash] options
|
||||
# @return [Hash{Symbol, Object}]
|
||||
#
|
||||
# @api private
|
||||
def parse_relationship(assoc_name, assoc_data, options)
|
||||
prefix_key = field_key(assoc_name, options).to_s.singularize
|
||||
hash =
|
||||
if assoc_data.is_a?(Array)
|
||||
{ "#{prefix_key}_ids".to_sym => assoc_data.map { |ri| ri['id'] } }
|
||||
else
|
||||
{ "#{prefix_key}_id".to_sym => assoc_data ? assoc_data['id'] : nil }
|
||||
end
|
||||
|
||||
polymorphic = (options[:polymorphic] || []).include?(assoc_name.to_sym)
|
||||
hash.merge!("#{prefix_key}_type".to_sym => assoc_data['type']) if polymorphic
|
||||
|
||||
hash
|
||||
end
|
||||
|
||||
# @api private
|
||||
def parse_relationships(relationships, options)
|
||||
relationships
|
||||
.map { |(k, v)| parse_relationship(k, v['data'], options) }
|
||||
.reduce({}, :merge)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,21 +0,0 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class FragmentCache
|
||||
def fragment_cache(root, cached_hash, non_cached_hash)
|
||||
hash = {}
|
||||
core_cached = cached_hash.first
|
||||
core_non_cached = non_cached_hash.first
|
||||
no_root_cache = cached_hash.delete_if { |key, value| key == core_cached[0] }
|
||||
no_root_non_cache = non_cached_hash.delete_if { |key, value| key == core_non_cached[0] }
|
||||
cached_resource = (core_cached[1]) ? core_cached[1].deep_merge(core_non_cached[1]) : core_non_cached[1]
|
||||
hash = (root) ? { root => cached_resource } : cached_resource
|
||||
|
||||
hash.deep_merge no_root_non_cache.deep_merge no_root_cache
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,45 +0,0 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class Link
|
||||
def initialize(serializer, value)
|
||||
@object = serializer.object
|
||||
@scope = serializer.scope
|
||||
|
||||
# Use the return value of the block unless it is nil.
|
||||
if value.respond_to?(:call)
|
||||
@value = instance_eval(&value)
|
||||
else
|
||||
@value = value
|
||||
end
|
||||
end
|
||||
|
||||
def href(value)
|
||||
@href = value
|
||||
nil
|
||||
end
|
||||
|
||||
def meta(value)
|
||||
@meta = value
|
||||
nil
|
||||
end
|
||||
|
||||
def as_json
|
||||
return @value if @value
|
||||
|
||||
hash = {}
|
||||
hash[:href] = @href if @href
|
||||
hash[:meta] = @meta if @meta
|
||||
|
||||
hash
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
attr_reader :object, :scope
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,58 +0,0 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class JsonApi < Base
|
||||
class PaginationLinks
|
||||
FIRST_PAGE = 1
|
||||
|
||||
attr_reader :collection, :context
|
||||
|
||||
def initialize(collection, context)
|
||||
@collection = collection
|
||||
@context = context
|
||||
end
|
||||
|
||||
def serializable_hash(options = {})
|
||||
pages_from.each_with_object({}) do |(key, value), hash|
|
||||
params = query_parameters.merge(page: { number: value, size: collection.size }).to_query
|
||||
|
||||
hash[key] = "#{url(options)}?#{params}"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def pages_from
|
||||
return {} if collection.total_pages == FIRST_PAGE
|
||||
|
||||
{}.tap do |pages|
|
||||
pages[:self] = collection.current_page
|
||||
|
||||
unless collection.current_page == FIRST_PAGE
|
||||
pages[:first] = FIRST_PAGE
|
||||
pages[:prev] = collection.current_page - FIRST_PAGE
|
||||
end
|
||||
|
||||
unless collection.current_page == collection.total_pages
|
||||
pages[:next] = collection.current_page + FIRST_PAGE
|
||||
pages[:last] = collection.total_pages
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def url(options)
|
||||
@url ||= options.fetch(:links, {}).fetch(:self, nil) || request_url
|
||||
end
|
||||
|
||||
def request_url
|
||||
@request_url ||= context.request_url
|
||||
end
|
||||
|
||||
def query_parameters
|
||||
@query_parameters ||= context.query_parameters
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,11 +0,0 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class Null < Base
|
||||
def serializable_hash(options = nil)
|
||||
{}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -9,6 +9,7 @@ module ActiveModelSerializers
|
||||
autoload :Deserialization
|
||||
autoload :Logging
|
||||
autoload :Test
|
||||
autoload :Adapter
|
||||
|
||||
class << self; attr_accessor :logger; end
|
||||
self.logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDOUT))
|
||||
|
||||
93
lib/active_model_serializers/adapter.rb
Normal file
93
lib/active_model_serializers/adapter.rb
Normal file
@ -0,0 +1,93 @@
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
UnknownAdapterError = Class.new(ArgumentError)
|
||||
ADAPTER_MAP = {}
|
||||
private_constant :ADAPTER_MAP if defined?(private_constant)
|
||||
require 'active_model_serializers/adapter/fragment_cache'
|
||||
require 'active_model_serializers/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 configured_adapter
|
||||
lookup(ActiveModelSerializers.config.adapter)
|
||||
end
|
||||
|
||||
def create(resource, options = {})
|
||||
override = options.delete(:adapter)
|
||||
klass = override ? adapter_class(override) : configured_adapter
|
||||
klass.new(resource, options)
|
||||
end
|
||||
|
||||
# @see ActiveModelSerializers::Adapter.lookup
|
||||
def adapter_class(adapter)
|
||||
ActiveModelSerializers::Adapter.lookup(adapter)
|
||||
end
|
||||
|
||||
# @return Hash<adapter_name, adapter_class>
|
||||
def adapter_map
|
||||
ADAPTER_MAP
|
||||
end
|
||||
|
||||
# @return [Array<Symbol>] list of adapter names
|
||||
def adapters
|
||||
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 'ActiveModelSerializers::Adapter::'
|
||||
# so that registering 'ActiveModelSerializers::Adapter::Json' and
|
||||
# 'Json' will both register as 'json'.
|
||||
def register(name, klass = name)
|
||||
name = name.to_s.gsub(/\AActiveModelSerializers::Adapter::/, ''.freeze)
|
||||
adapter_map.update(name.underscore => klass)
|
||||
self
|
||||
end
|
||||
|
||||
# @param adapter [String, Symbol, Class] name to fetch adapter by
|
||||
# @return [ActiveModelSerializers::Adapter] subclass of Adapter
|
||||
# @raise [UnknownAdapterError]
|
||||
def lookup(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')
|
||||
"ActiveModelSerializers::Adapter::#{adapter_name}".safe_constantize ||
|
||||
"ActiveModelSerializers::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_serializers/adapter/base'
|
||||
require 'active_model_serializers/adapter/null'
|
||||
require 'active_model_serializers/adapter/attributes'
|
||||
require 'active_model_serializers/adapter/json'
|
||||
require 'active_model_serializers/adapter/json_api'
|
||||
end
|
||||
end
|
||||
98
lib/active_model_serializers/adapter/attributes.rb
Normal file
98
lib/active_model_serializers/adapter/attributes.rb
Normal file
@ -0,0 +1,98 @@
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class Attributes < Base
|
||||
def initialize(serializer, options = {})
|
||||
super
|
||||
@include_tree = ActiveModel::Serializer::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
|
||||
56
lib/active_model_serializers/adapter/base.rb
Normal file
56
lib/active_model_serializers/adapter/base.rb
Normal file
@ -0,0 +1,56 @@
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class Base
|
||||
# Automatically register adapters when subclassing
|
||||
def self.inherited(subclass)
|
||||
ActiveModelSerializers::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
|
||||
77
lib/active_model_serializers/adapter/cached_serializer.rb
Normal file
77
lib/active_model_serializers/adapter/cached_serializer.rb
Normal file
@ -0,0 +1,77 @@
|
||||
module ActiveModelSerializers
|
||||
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
|
||||
113
lib/active_model_serializers/adapter/fragment_cache.rb
Normal file
113
lib/active_model_serializers/adapter/fragment_cache.rb
Normal file
@ -0,0 +1,113 @@
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class FragmentCache
|
||||
attr_reader :serializer
|
||||
|
||||
def initialize(adapter, serializer, options)
|
||||
@instance_options = options
|
||||
@adapter = adapter
|
||||
@serializer = serializer
|
||||
end
|
||||
|
||||
# TODO: Use Serializable::Resource
|
||||
# TODO: call +constantize+ less
|
||||
# 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
|
||||
klass = serializer.class
|
||||
# It will split the serializer into two, one that will be cached and one that will not
|
||||
serializers = fragment_serializer(serializer.object.class.name, klass)
|
||||
|
||||
# Instantiate both serializers
|
||||
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, 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)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
attr_reader :instance_options, :adapter
|
||||
|
||||
private
|
||||
|
||||
# Given a serializer class and 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 cached_attributes(klass, serializers)
|
||||
attributes = serializer.class._attributes
|
||||
cached_attributes = (klass._cache_only) ? klass._cache_only : attributes.reject { |attr| klass._cache_except.include?(attr) }
|
||||
non_cached_attributes = attributes - cached_attributes
|
||||
|
||||
cached_attributes.each do |attribute|
|
||||
options = serializer.class._attributes_keys[attribute]
|
||||
options ||= {}
|
||||
# Add cached attributes to cached Serializer
|
||||
serializers[:cached].constantize.attribute(attribute, options)
|
||||
end
|
||||
|
||||
non_cached_attributes.each do |attribute|
|
||||
options = serializer.class._attributes_keys[attribute]
|
||||
options ||= {}
|
||||
# Add non-cached attributes to non-cached Serializer
|
||||
serializers[:non_cached].constantize.attribute(attribute, options)
|
||||
end
|
||||
end
|
||||
|
||||
# Given a resource name and its serializer's class
|
||||
# 1. Dyanmically creates a CachedSerializer and NonCachedSerializer
|
||||
# for a given class 'name'
|
||||
# 2. Call
|
||||
# CachedSerializer.cache(serializer._cache_options)
|
||||
# CachedSerializer.fragmented(serializer)
|
||||
# NontCachedSerializer.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 <tt>User::Admin</tt>
|
||||
# creates the Serializer classes (if they don't exist).
|
||||
# User_AdminCachedSerializer
|
||||
# User_AdminNOnCachedSerializer
|
||||
#
|
||||
def fragment_serializer(name, klass)
|
||||
cached = "#{to_valid_const_name(name)}CachedSerializer"
|
||||
non_cached = "#{to_valid_const_name(name)}NonCachedSerializer"
|
||||
|
||||
Object.const_set cached, Class.new(ActiveModel::Serializer) unless Object.const_defined?(cached)
|
||||
Object.const_set non_cached, Class.new(ActiveModel::Serializer) unless Object.const_defined?(non_cached)
|
||||
|
||||
klass._cache_options ||= {}
|
||||
klass._cache_options[:key] = klass._cache_key if klass._cache_key
|
||||
|
||||
cached.constantize.cache(klass._cache_options)
|
||||
|
||||
# Preserve the type setting in the cached/non-cached serializer classes
|
||||
cached.constantize.type(klass._type)
|
||||
non_cached.constantize.type(klass._type)
|
||||
|
||||
cached.constantize.fragmented(serializer)
|
||||
non_cached.constantize.fragmented(serializer)
|
||||
|
||||
serializers = { cached: cached, non_cached: non_cached }
|
||||
cached_attributes(klass, serializers)
|
||||
serializers
|
||||
end
|
||||
|
||||
def to_valid_const_name(name)
|
||||
name.gsub('::', '_')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
19
lib/active_model_serializers/adapter/json.rb
Normal file
19
lib/active_model_serializers/adapter/json.rb
Normal file
@ -0,0 +1,19 @@
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class Json < Base
|
||||
extend ActiveSupport::Autoload
|
||||
autoload :FragmentCache
|
||||
|
||||
def serializable_hash(options = nil)
|
||||
options ||= {}
|
||||
{ root => Attributes.new(serializer, instance_options).serializable_hash(options) }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fragment_cache(cached_hash, non_cached_hash)
|
||||
ActiveModelSerializers::Adapter::Json::FragmentCache.new.fragment_cache(cached_hash, non_cached_hash)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
11
lib/active_model_serializers/adapter/json/fragment_cache.rb
Normal file
11
lib/active_model_serializers/adapter/json/fragment_cache.rb
Normal file
@ -0,0 +1,11 @@
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class Json
|
||||
class FragmentCache
|
||||
def fragment_cache(cached_hash, non_cached_hash)
|
||||
non_cached_hash.merge cached_hash
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
186
lib/active_model_serializers/adapter/json_api.rb
Normal file
186
lib/active_model_serializers/adapter/json_api.rb
Normal file
@ -0,0 +1,186 @@
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi < Base
|
||||
extend ActiveSupport::Autoload
|
||||
autoload :PaginationLinks
|
||||
autoload :FragmentCache
|
||||
autoload :Link
|
||||
require 'active_model/serializer/adapter/json_api/meta'
|
||||
autoload :Deserialization
|
||||
require 'active_model/serializer/adapter/json_api/api_objects'
|
||||
|
||||
# TODO: if we like this abstraction and other API objects to it,
|
||||
# then extract to its own file and require it.
|
||||
module ApiObjects
|
||||
module JsonApi
|
||||
ActiveModelSerializers.config.jsonapi_version = '1.0'
|
||||
ActiveModelSerializers.config.jsonapi_toplevel_meta = {}
|
||||
# Make JSON API top-level jsonapi member opt-in
|
||||
# ref: http://jsonapi.org/format/#document-top-level
|
||||
ActiveModelSerializers.config.jsonapi_include_toplevel_object = false
|
||||
|
||||
module_function
|
||||
|
||||
def add!(hash)
|
||||
hash.merge!(object) if include_object?
|
||||
end
|
||||
|
||||
def include_object?
|
||||
ActiveModelSerializers.config.jsonapi_include_toplevel_object
|
||||
end
|
||||
|
||||
# TODO: see if we can cache this
|
||||
def object
|
||||
object = {
|
||||
jsonapi: {
|
||||
version: ActiveModelSerializers.config.jsonapi_version,
|
||||
meta: ActiveModelSerializers.config.jsonapi_toplevel_meta
|
||||
}
|
||||
}
|
||||
object[:jsonapi].reject! { |_, v| v.blank? }
|
||||
|
||||
object
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(serializer, options = {})
|
||||
super
|
||||
@include_tree = ActiveModel::Serializer::IncludeTree.from_include_args(options[:include])
|
||||
@fieldset = options[:fieldset] || ActiveModel::Serializer::Fieldset.new(options.delete(:fields))
|
||||
end
|
||||
|
||||
def serializable_hash(options = nil)
|
||||
options ||= {}
|
||||
|
||||
is_collection = serializer.respond_to?(:each)
|
||||
serializers = is_collection ? serializer : [serializer]
|
||||
primary_data, included = resource_objects_for(serializers)
|
||||
|
||||
hash = {}
|
||||
hash[:data] = is_collection ? primary_data : primary_data[0]
|
||||
hash[:included] = included if included.any?
|
||||
|
||||
ApiObjects::JsonApi.add!(hash)
|
||||
|
||||
if instance_options[:links]
|
||||
hash[:links] ||= {}
|
||||
hash[:links].update(instance_options[:links])
|
||||
end
|
||||
|
||||
if is_collection && serializer.paginated?
|
||||
hash[:links] ||= {}
|
||||
hash[:links].update(pagination_links_for(serializer, options))
|
||||
end
|
||||
|
||||
hash
|
||||
end
|
||||
|
||||
def fragment_cache(cached_hash, non_cached_hash)
|
||||
root = false if instance_options.include?(:include)
|
||||
ActiveModelSerializers::Adapter::JsonApi::FragmentCache.new.fragment_cache(root, cached_hash, non_cached_hash)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
attr_reader :fieldset
|
||||
|
||||
private
|
||||
|
||||
def resource_objects_for(serializers)
|
||||
@primary = []
|
||||
@included = []
|
||||
@resource_identifiers = Set.new
|
||||
serializers.each { |serializer| process_resource(serializer, true) }
|
||||
serializers.each { |serializer| process_relationships(serializer, @include_tree) }
|
||||
|
||||
[@primary, @included]
|
||||
end
|
||||
|
||||
def process_resource(serializer, primary)
|
||||
resource_identifier = ActiveModel::Serializer::Adapter::JsonApi::ApiObjects::ResourceIdentifier.new(serializer).as_json
|
||||
return false unless @resource_identifiers.add?(resource_identifier)
|
||||
|
||||
resource_object = resource_object_for(serializer)
|
||||
if primary
|
||||
@primary << resource_object
|
||||
else
|
||||
@included << resource_object
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def process_relationships(serializer, include_tree)
|
||||
serializer.associations(include_tree).each do |association|
|
||||
process_relationship(association.serializer, include_tree[association.key])
|
||||
end
|
||||
end
|
||||
|
||||
def process_relationship(serializer, include_tree)
|
||||
if serializer.respond_to?(:each)
|
||||
serializer.each { |s| process_relationship(s, include_tree) }
|
||||
return
|
||||
end
|
||||
return unless serializer && serializer.object
|
||||
return unless process_resource(serializer, false)
|
||||
|
||||
process_relationships(serializer, include_tree)
|
||||
end
|
||||
|
||||
def attributes_for(serializer, fields)
|
||||
serializer.attributes(fields).except(:id)
|
||||
end
|
||||
|
||||
def resource_object_for(serializer)
|
||||
resource_object = cache_check(serializer) do
|
||||
resource_object = ActiveModel::Serializer::Adapter::JsonApi::ApiObjects::ResourceIdentifier.new(serializer).as_json
|
||||
|
||||
requested_fields = fieldset && fieldset.fields_for(resource_object[:type])
|
||||
attributes = attributes_for(serializer, requested_fields)
|
||||
resource_object[:attributes] = attributes if attributes.any?
|
||||
resource_object
|
||||
end
|
||||
|
||||
requested_associations = fieldset.fields_for(resource_object[:type]) || '*'
|
||||
relationships = relationships_for(serializer, requested_associations)
|
||||
resource_object[:relationships] = relationships if relationships.any?
|
||||
|
||||
links = links_for(serializer)
|
||||
resource_object[:links] = links if links.any?
|
||||
|
||||
meta = meta_for(serializer)
|
||||
resource_object[:meta] = meta unless meta.nil?
|
||||
|
||||
resource_object
|
||||
end
|
||||
|
||||
def relationships_for(serializer, requested_associations)
|
||||
include_tree = ActiveModel::Serializer::IncludeTree.from_include_args(requested_associations)
|
||||
serializer.associations(include_tree).each_with_object({}) do |association, hash|
|
||||
hash[association.key] = ActiveModel::Serializer::Adapter::JsonApi::ApiObjects::Relationship.new(
|
||||
serializer,
|
||||
association.serializer,
|
||||
association.options,
|
||||
association.links,
|
||||
association.meta
|
||||
).as_json
|
||||
end
|
||||
end
|
||||
|
||||
def links_for(serializer)
|
||||
serializer._links.each_with_object({}) do |(name, value), hash|
|
||||
hash[name] = Link.new(serializer, value).as_json
|
||||
end
|
||||
end
|
||||
|
||||
def pagination_links_for(serializer, options)
|
||||
JsonApi::PaginationLinks.new(serializer.object, options[:serialization_context]).serializable_hash(options)
|
||||
end
|
||||
|
||||
def meta_for(serializer)
|
||||
ActiveModel::Serializer::Adapter::JsonApi::Meta.new(serializer).as_json
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
205
lib/active_model_serializers/adapter/json_api/deserialization.rb
Normal file
205
lib/active_model_serializers/adapter/json_api/deserialization.rb
Normal file
@ -0,0 +1,205 @@
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi
|
||||
# NOTE(Experimental):
|
||||
# This is an experimental feature. Both the interface and internals could be subject
|
||||
# to changes.
|
||||
module Deserialization
|
||||
InvalidDocument = Class.new(ArgumentError)
|
||||
|
||||
module_function
|
||||
|
||||
# Transform a JSON API document, containing a single data object,
|
||||
# into a hash that is ready for ActiveRecord::Base.new() and such.
|
||||
# Raises InvalidDocument if the payload is not properly formatted.
|
||||
#
|
||||
# @param [Hash|ActionController::Parameters] document
|
||||
# @param [Hash] options
|
||||
# only: Array of symbols of whitelisted fields.
|
||||
# except: Array of symbols of blacklisted fields.
|
||||
# keys: Hash of translated keys (e.g. :author => :user).
|
||||
# polymorphic: Array of symbols of polymorphic fields.
|
||||
# @return [Hash]
|
||||
#
|
||||
# @example
|
||||
# document = {
|
||||
# data: {
|
||||
# id: 1,
|
||||
# type: 'post',
|
||||
# attributes: {
|
||||
# title: 'Title 1',
|
||||
# date: '2015-12-20'
|
||||
# },
|
||||
# associations: {
|
||||
# author: {
|
||||
# data: {
|
||||
# type: 'user',
|
||||
# id: 2
|
||||
# }
|
||||
# },
|
||||
# second_author: {
|
||||
# data: nil
|
||||
# },
|
||||
# comments: {
|
||||
# data: [{
|
||||
# type: 'comment',
|
||||
# id: 3
|
||||
# },{
|
||||
# type: 'comment',
|
||||
# id: 4
|
||||
# }]
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# parse(document) #=>
|
||||
# # {
|
||||
# # title: 'Title 1',
|
||||
# # date: '2015-12-20',
|
||||
# # author_id: 2,
|
||||
# # second_author_id: nil
|
||||
# # comment_ids: [3, 4]
|
||||
# # }
|
||||
#
|
||||
# parse(document, only: [:title, :date, :author],
|
||||
# keys: { date: :published_at },
|
||||
# polymorphic: [:author]) #=>
|
||||
# # {
|
||||
# # title: 'Title 1',
|
||||
# # published_at: '2015-12-20',
|
||||
# # author_id: '2',
|
||||
# # author_type: 'people'
|
||||
# # }
|
||||
#
|
||||
def parse!(document, options = {})
|
||||
parse(document, options) do |invalid_payload, reason|
|
||||
fail InvalidDocument, "Invalid payload (#{reason}): #{invalid_payload}"
|
||||
end
|
||||
end
|
||||
|
||||
# Same as parse!, but returns an empty hash instead of raising InvalidDocument
|
||||
# on invalid payloads.
|
||||
def parse(document, options = {})
|
||||
document = document.dup.permit!.to_h if document.is_a?(ActionController::Parameters)
|
||||
|
||||
validate_payload(document) do |invalid_document, reason|
|
||||
yield invalid_document, reason if block_given?
|
||||
return {}
|
||||
end
|
||||
|
||||
primary_data = document['data']
|
||||
attributes = primary_data['attributes'] || {}
|
||||
attributes['id'] = primary_data['id'] if primary_data['id']
|
||||
relationships = primary_data['relationships'] || {}
|
||||
|
||||
filter_fields(attributes, options)
|
||||
filter_fields(relationships, options)
|
||||
|
||||
hash = {}
|
||||
hash.merge!(parse_attributes(attributes, options))
|
||||
hash.merge!(parse_relationships(relationships, options))
|
||||
|
||||
hash
|
||||
end
|
||||
|
||||
# Checks whether a payload is compliant with the JSON API spec.
|
||||
#
|
||||
# @api private
|
||||
# rubocop:disable Metrics/CyclomaticComplexity
|
||||
def validate_payload(payload)
|
||||
unless payload.is_a?(Hash)
|
||||
yield payload, 'Expected hash'
|
||||
return
|
||||
end
|
||||
|
||||
primary_data = payload['data']
|
||||
unless primary_data.is_a?(Hash)
|
||||
yield payload, { data: 'Expected hash' }
|
||||
return
|
||||
end
|
||||
|
||||
attributes = primary_data['attributes'] || {}
|
||||
unless attributes.is_a?(Hash)
|
||||
yield payload, { data: { attributes: 'Expected hash or nil' } }
|
||||
return
|
||||
end
|
||||
|
||||
relationships = primary_data['relationships'] || {}
|
||||
unless relationships.is_a?(Hash)
|
||||
yield payload, { data: { relationships: 'Expected hash or nil' } }
|
||||
return
|
||||
end
|
||||
|
||||
relationships.each do |(key, value)|
|
||||
unless value.is_a?(Hash) && value.key?('data')
|
||||
yield payload, { data: { relationships: { key => 'Expected hash with :data key' } } }
|
||||
end
|
||||
end
|
||||
end
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
|
||||
# @api private
|
||||
def filter_fields(fields, options)
|
||||
if (only = options[:only])
|
||||
fields.slice!(*Array(only).map(&:to_s))
|
||||
elsif (except = options[:except])
|
||||
fields.except!(*Array(except).map(&:to_s))
|
||||
end
|
||||
end
|
||||
|
||||
# @api private
|
||||
def field_key(field, options)
|
||||
(options[:keys] || {}).fetch(field.to_sym, field).to_sym
|
||||
end
|
||||
|
||||
# @api private
|
||||
def parse_attributes(attributes, options)
|
||||
attributes
|
||||
.map { |(k, v)| { field_key(k, options) => v } }
|
||||
.reduce({}, :merge)
|
||||
end
|
||||
|
||||
# Given an association name, and a relationship data attribute, build a hash
|
||||
# mapping the corresponding ActiveRecord attribute to the corresponding value.
|
||||
#
|
||||
# @example
|
||||
# parse_relationship(:comments, [{ 'id' => '1', 'type' => 'comments' },
|
||||
# { 'id' => '2', 'type' => 'comments' }],
|
||||
# {})
|
||||
# # => { :comment_ids => ['1', '2'] }
|
||||
# parse_relationship(:author, { 'id' => '1', 'type' => 'users' }, {})
|
||||
# # => { :author_id => '1' }
|
||||
# parse_relationship(:author, nil, {})
|
||||
# # => { :author_id => nil }
|
||||
# @param [Symbol] assoc_name
|
||||
# @param [Hash] assoc_data
|
||||
# @param [Hash] options
|
||||
# @return [Hash{Symbol, Object}]
|
||||
#
|
||||
# @api private
|
||||
def parse_relationship(assoc_name, assoc_data, options)
|
||||
prefix_key = field_key(assoc_name, options).to_s.singularize
|
||||
hash =
|
||||
if assoc_data.is_a?(Array)
|
||||
{ "#{prefix_key}_ids".to_sym => assoc_data.map { |ri| ri['id'] } }
|
||||
else
|
||||
{ "#{prefix_key}_id".to_sym => assoc_data ? assoc_data['id'] : nil }
|
||||
end
|
||||
|
||||
polymorphic = (options[:polymorphic] || []).include?(assoc_name.to_sym)
|
||||
hash.merge!("#{prefix_key}_type".to_sym => assoc_data['type']) if polymorphic
|
||||
|
||||
hash
|
||||
end
|
||||
|
||||
# @api private
|
||||
def parse_relationships(relationships, options)
|
||||
relationships
|
||||
.map { |(k, v)| parse_relationship(k, v['data'], options) }
|
||||
.reduce({}, :merge)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,18 @@
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class FragmentCache
|
||||
def fragment_cache(root, cached_hash, non_cached_hash)
|
||||
core_cached = cached_hash.first
|
||||
core_non_cached = non_cached_hash.first
|
||||
no_root_cache = cached_hash.delete_if { |key, _value| key == core_cached[0] }
|
||||
no_root_non_cache = non_cached_hash.delete_if { |key, _value| key == core_non_cached[0] }
|
||||
cached_resource = (core_cached[1]) ? core_cached[1].deep_merge(core_non_cached[1]) : core_non_cached[1]
|
||||
hash = (root) ? { root => cached_resource } : cached_resource
|
||||
|
||||
hash.deep_merge no_root_non_cache.deep_merge no_root_cache
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
43
lib/active_model_serializers/adapter/json_api/link.rb
Normal file
43
lib/active_model_serializers/adapter/json_api/link.rb
Normal file
@ -0,0 +1,43 @@
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class Link
|
||||
def initialize(serializer, value)
|
||||
@object = serializer.object
|
||||
@scope = serializer.scope
|
||||
|
||||
# Use the return value of the block unless it is nil.
|
||||
if value.respond_to?(:call)
|
||||
@value = instance_eval(&value)
|
||||
else
|
||||
@value = value
|
||||
end
|
||||
end
|
||||
|
||||
def href(value)
|
||||
@href = value
|
||||
nil
|
||||
end
|
||||
|
||||
def meta(value)
|
||||
@meta = value
|
||||
nil
|
||||
end
|
||||
|
||||
def as_json
|
||||
return @value if @value
|
||||
|
||||
hash = {}
|
||||
hash[:href] = @href if @href
|
||||
hash[:meta] = @meta if @meta
|
||||
|
||||
hash
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
attr_reader :object, :scope
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,56 @@
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi < Base
|
||||
class PaginationLinks
|
||||
FIRST_PAGE = 1
|
||||
|
||||
attr_reader :collection, :context
|
||||
|
||||
def initialize(collection, context)
|
||||
@collection = collection
|
||||
@context = context
|
||||
end
|
||||
|
||||
def serializable_hash(options = {})
|
||||
pages_from.each_with_object({}) do |(key, value), hash|
|
||||
params = query_parameters.merge(page: { number: value, size: collection.size }).to_query
|
||||
|
||||
hash[key] = "#{url(options)}?#{params}"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def pages_from
|
||||
return {} if collection.total_pages == FIRST_PAGE
|
||||
|
||||
{}.tap do |pages|
|
||||
pages[:self] = collection.current_page
|
||||
|
||||
unless collection.current_page == FIRST_PAGE
|
||||
pages[:first] = FIRST_PAGE
|
||||
pages[:prev] = collection.current_page - FIRST_PAGE
|
||||
end
|
||||
|
||||
unless collection.current_page == collection.total_pages
|
||||
pages[:next] = collection.current_page + FIRST_PAGE
|
||||
pages[:last] = collection.total_pages
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def url(options)
|
||||
@url ||= options.fetch(:links, {}).fetch(:self, nil) || request_url
|
||||
end
|
||||
|
||||
def request_url
|
||||
@request_url ||= context.request_url
|
||||
end
|
||||
|
||||
def query_parameters
|
||||
@query_parameters ||= context.query_parameters
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
10
lib/active_model_serializers/adapter/null.rb
Normal file
10
lib/active_model_serializers/adapter/null.rb
Normal file
@ -0,0 +1,10 @@
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class Null < Base
|
||||
# Since options param is not being used, underscored naming of the param
|
||||
def serializable_hash(_options = nil)
|
||||
{}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -3,11 +3,11 @@ module ActiveModelSerializers
|
||||
module_function
|
||||
|
||||
def jsonapi_parse(*args)
|
||||
ActiveModel::Serializer::Adapter::JsonApi::Deserialization.parse(*args)
|
||||
ActiveModelSerializers::Adapter::JsonApi::Deserialization.parse(*args)
|
||||
end
|
||||
|
||||
def jsonapi_parse!(*args)
|
||||
ActiveModel::Serializer::Adapter::JsonApi::Deserialization.parse!(*args)
|
||||
ActiveModelSerializers::Adapter::JsonApi::Deserialization.parse!(*args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -3,7 +3,6 @@ require 'test_helper'
|
||||
module ActionController
|
||||
module Serialization
|
||||
class ImplicitSerializerTest < ActionController::TestCase
|
||||
include ActiveSupport::Testing::Stream
|
||||
class ImplicitSerializationTestController < ActionController::Base
|
||||
include SerializationTesting
|
||||
def render_using_implicit_serializer
|
||||
@ -46,7 +45,7 @@ module ActionController
|
||||
end
|
||||
|
||||
def render_array_using_implicit_serializer_and_links
|
||||
with_adapter ActiveModel::Serializer::Adapter::JsonApi do
|
||||
with_adapter ActiveModelSerializers::Adapter::JsonApi do
|
||||
@profiles = [
|
||||
Profile.new(name: 'Name 1', description: 'Description 1', comments: 'Comments 1')
|
||||
]
|
||||
@ -438,9 +437,9 @@ module ActionController
|
||||
false
|
||||
end
|
||||
end.new
|
||||
assert_match(/adapter: false/, (capture(:stderr) do
|
||||
assert_output(nil, /adapter: false/) do
|
||||
controller.get_serializer(Profile.new)
|
||||
end))
|
||||
end
|
||||
end
|
||||
|
||||
def test_dont_warn_overridding_use_adapter_as_truthy_on_controller_instance
|
||||
@ -449,9 +448,9 @@ module ActionController
|
||||
true
|
||||
end
|
||||
end.new
|
||||
assert_equal '', (capture(:stderr) do
|
||||
assert_output(nil, '') do
|
||||
controller.get_serializer(Profile.new)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
def test_render_event_is_emmited
|
||||
|
||||
203
test/active_model_serializers/adapter_for_test.rb
Normal file
203
test/active_model_serializers/adapter_for_test.rb
Normal file
@ -0,0 +1,203 @@
|
||||
module ActiveModelSerializers
|
||||
class AdapterForTest < ActiveSupport::TestCase
|
||||
UnknownAdapterError = ::ActiveModelSerializers::Adapter::UnknownAdapterError
|
||||
|
||||
def setup
|
||||
@previous_adapter = ActiveModelSerializers.config.adapter
|
||||
end
|
||||
|
||||
def teardown
|
||||
ActiveModelSerializers.config.adapter = @previous_adapter
|
||||
end
|
||||
|
||||
def test_serializer_adapter_returns_configured__adapter
|
||||
assert_output(nil, /ActiveModelSerializers::configured_adapter/) do
|
||||
assert_equal ActiveModelSerializers::Adapter.configured_adapter, ActiveModel::Serializer.adapter
|
||||
end
|
||||
end
|
||||
|
||||
def test_returns_default_adapter
|
||||
adapter = ActiveModelSerializers::Adapter.configured_adapter
|
||||
assert_equal ActiveModelSerializers::Adapter::Attributes, adapter
|
||||
end
|
||||
|
||||
def test_overwrite_adapter_with_symbol
|
||||
ActiveModelSerializers.config.adapter = :null
|
||||
|
||||
adapter = ActiveModelSerializers::Adapter.configured_adapter
|
||||
assert_equal ActiveModelSerializers::Adapter::Null, adapter
|
||||
ensure
|
||||
ActiveModelSerializers.config.adapter = @previous_adapter
|
||||
end
|
||||
|
||||
def test_overwrite_adapter_with_camelcased_symbol
|
||||
ActiveModelSerializers.config.adapter = :JsonApi
|
||||
|
||||
adapter = ActiveModelSerializers::Adapter.configured_adapter
|
||||
assert_equal ActiveModelSerializers::Adapter::JsonApi, adapter
|
||||
ensure
|
||||
ActiveModelSerializers.config.adapter = @previous_adapter
|
||||
end
|
||||
|
||||
def test_overwrite_adapter_with_string
|
||||
ActiveModelSerializers.config.adapter = 'json_api'
|
||||
|
||||
adapter = ActiveModelSerializers::Adapter.configured_adapter
|
||||
assert_equal ActiveModelSerializers::Adapter::JsonApi, adapter
|
||||
ensure
|
||||
ActiveModelSerializers.config.adapter = @previous_adapter
|
||||
end
|
||||
|
||||
def test_overwrite_adapter_with_a_camelcased_string
|
||||
ActiveModelSerializers.config.adapter = 'JsonApi'
|
||||
|
||||
adapter = ActiveModelSerializers::Adapter.configured_adapter
|
||||
assert_equal ActiveModelSerializers::Adapter::JsonApi, adapter
|
||||
ensure
|
||||
ActiveModelSerializers.config.adapter = @previous_adapter
|
||||
end
|
||||
|
||||
def test_overwrite_adapter_with_class
|
||||
ActiveModelSerializers.config.adapter = ActiveModelSerializers::Adapter::Null
|
||||
|
||||
adapter = ActiveModelSerializers::Adapter.configured_adapter
|
||||
assert_equal ActiveModelSerializers::Adapter::Null, adapter
|
||||
ensure
|
||||
ActiveModelSerializers.config.adapter = @previous_adapter
|
||||
end
|
||||
|
||||
def test_raises_exception_if_invalid_symbol_given
|
||||
ActiveModelSerializers.config.adapter = :unknown
|
||||
|
||||
assert_raises UnknownAdapterError do
|
||||
ActiveModelSerializers::Adapter.configured_adapter
|
||||
end
|
||||
ensure
|
||||
ActiveModelSerializers.config.adapter = @previous_adapter
|
||||
end
|
||||
|
||||
def test_raises_exception_if_it_does_not_know_hot_to_infer_adapter
|
||||
ActiveModelSerializers.config.adapter = 42
|
||||
|
||||
assert_raises UnknownAdapterError do
|
||||
ActiveModelSerializers::Adapter.configured_adapter
|
||||
end
|
||||
ensure
|
||||
ActiveModelSerializers.config.adapter = @previous_adapter
|
||||
end
|
||||
|
||||
def test_adapter_class_for_known_adapter
|
||||
klass = ActiveModelSerializers::Adapter.adapter_class(:json_api)
|
||||
assert_equal ActiveModelSerializers::Adapter::JsonApi, klass
|
||||
end
|
||||
|
||||
def test_adapter_class_for_unknown_adapter
|
||||
assert_raises UnknownAdapterError do
|
||||
ActiveModelSerializers::Adapter.adapter_class(:json_simple)
|
||||
end
|
||||
end
|
||||
|
||||
def test_adapter_map
|
||||
expected_adapter_map = {
|
||||
'null'.freeze => ActiveModelSerializers::Adapter::Null,
|
||||
'json'.freeze => ActiveModelSerializers::Adapter::Json,
|
||||
'attributes'.freeze => ActiveModelSerializers::Adapter::Attributes,
|
||||
'json_api'.freeze => ActiveModelSerializers::Adapter::JsonApi
|
||||
}
|
||||
actual = ActiveModelSerializers::Adapter.adapter_map
|
||||
assert_equal actual, expected_adapter_map
|
||||
end
|
||||
|
||||
def test_adapters
|
||||
assert_equal ActiveModelSerializers::Adapter.adapters.sort, [
|
||||
'attributes'.freeze,
|
||||
'json'.freeze,
|
||||
'json_api'.freeze,
|
||||
'null'.freeze
|
||||
]
|
||||
end
|
||||
|
||||
def test_lookup_adapter_by_string_name
|
||||
assert_equal ActiveModelSerializers::Adapter.lookup('json'.freeze), ActiveModelSerializers::Adapter::Json
|
||||
end
|
||||
|
||||
def test_lookup_adapter_by_symbol_name
|
||||
assert_equal ActiveModelSerializers::Adapter.lookup(:json), ActiveModelSerializers::Adapter::Json
|
||||
end
|
||||
|
||||
def test_lookup_adapter_by_class
|
||||
klass = ActiveModelSerializers::Adapter::Json
|
||||
assert_equal ActiveModelSerializers::Adapter.lookup(klass), klass
|
||||
end
|
||||
|
||||
def test_lookup_adapter_from_environment_registers_adapter
|
||||
ActiveModelSerializers::Adapter.const_set(:AdapterFromEnvironment, Class.new)
|
||||
klass = ::ActiveModelSerializers::Adapter::AdapterFromEnvironment
|
||||
name = 'adapter_from_environment'.freeze
|
||||
assert_equal ActiveModelSerializers::Adapter.lookup(name), klass
|
||||
assert ActiveModelSerializers::Adapter.adapters.include?(name)
|
||||
ensure
|
||||
ActiveModelSerializers::Adapter.adapter_map.delete(name)
|
||||
ActiveModelSerializers::Adapter.send(:remove_const, :AdapterFromEnvironment)
|
||||
end
|
||||
|
||||
def test_lookup_adapter_for_unknown_name
|
||||
assert_raises UnknownAdapterError do
|
||||
ActiveModelSerializers::Adapter.lookup(:json_simple)
|
||||
end
|
||||
end
|
||||
|
||||
def test_adapter
|
||||
assert_equal ActiveModelSerializers.config.adapter, :attributes
|
||||
assert_equal ActiveModelSerializers::Adapter.configured_adapter, ActiveModelSerializers::Adapter::Attributes
|
||||
end
|
||||
|
||||
def test_register_adapter
|
||||
new_adapter_name = :foo
|
||||
new_adapter_klass = Class.new
|
||||
ActiveModelSerializers::Adapter.register(new_adapter_name, new_adapter_klass)
|
||||
assert ActiveModelSerializers::Adapter.adapters.include?('foo'.freeze)
|
||||
assert ActiveModelSerializers::Adapter.lookup(:foo), new_adapter_klass
|
||||
ensure
|
||||
ActiveModelSerializers::Adapter.adapter_map.delete(new_adapter_name.to_s)
|
||||
end
|
||||
|
||||
def test_inherited_adapter_hooks_register_adapter
|
||||
Object.const_set(:MyAdapter, Class.new)
|
||||
my_adapter = MyAdapter
|
||||
ActiveModelSerializers::Adapter::Base.inherited(my_adapter)
|
||||
assert_equal ActiveModelSerializers::Adapter.lookup(:my_adapter), my_adapter
|
||||
ensure
|
||||
ActiveModelSerializers::Adapter.adapter_map.delete('my_adapter'.freeze)
|
||||
Object.send(:remove_const, :MyAdapter)
|
||||
end
|
||||
|
||||
def test_inherited_adapter_hooks_register_namespaced_adapter
|
||||
Object.const_set(:MyNamespace, Module.new)
|
||||
MyNamespace.const_set(:MyAdapter, Class.new)
|
||||
my_adapter = MyNamespace::MyAdapter
|
||||
ActiveModelSerializers::Adapter::Base.inherited(my_adapter)
|
||||
assert_equal ActiveModelSerializers::Adapter.lookup(:'my_namespace/my_adapter'), my_adapter
|
||||
ensure
|
||||
ActiveModelSerializers::Adapter.adapter_map.delete('my_namespace/my_adapter'.freeze)
|
||||
MyNamespace.send(:remove_const, :MyAdapter)
|
||||
Object.send(:remove_const, :MyNamespace)
|
||||
end
|
||||
|
||||
def test_inherited_adapter_hooks_register_subclass_of_registered_adapter
|
||||
Object.const_set(:MyAdapter, Class.new)
|
||||
my_adapter = MyAdapter
|
||||
Object.const_set(:MySubclassedAdapter, Class.new(MyAdapter))
|
||||
my_subclassed_adapter = MySubclassedAdapter
|
||||
ActiveModelSerializers::Adapter::Base.inherited(my_adapter)
|
||||
ActiveModelSerializers::Adapter::Base.inherited(my_subclassed_adapter)
|
||||
assert_equal ActiveModelSerializers::Adapter.lookup(:my_adapter), my_adapter
|
||||
assert_equal ActiveModelSerializers::Adapter.lookup(:my_subclassed_adapter), my_subclassed_adapter
|
||||
ensure
|
||||
ActiveModelSerializers::Adapter.adapter_map.delete('my_adapter'.freeze)
|
||||
ActiveModelSerializers::Adapter.adapter_map.delete('my_subclassed_adapter'.freeze)
|
||||
Object.send(:remove_const, :MyAdapter)
|
||||
Object.send(:remove_const, :MySubclassedAdapter)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -65,7 +65,7 @@ module ActiveModel
|
||||
|
||||
def test_logs_correct_adapter
|
||||
ActiveModel::SerializableResource.new(@post).serializable_hash
|
||||
assert_match(/ActiveModel::Serializer::Adapter::Attributes/, @logger.messages)
|
||||
assert_match(/ActiveModelSerializers::Adapter::Attributes/, @logger.messages)
|
||||
end
|
||||
|
||||
def test_logs_the_duration
|
||||
|
||||
@ -1,49 +1,47 @@
|
||||
require 'test_helper'
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class FragmentCacheTest < ActiveSupport::TestCase
|
||||
TypedRoleSerializer = Class.new(ActiveModel::Serializer) do
|
||||
type 'my-roles'
|
||||
cache only: [:name], skip_digest: true
|
||||
attributes :id, :name, :description
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class FragmentCacheTest < ActiveSupport::TestCase
|
||||
TypedRoleSerializer = Class.new(ActiveModel::Serializer) do
|
||||
type 'my-roles'
|
||||
cache only: [:name], skip_digest: true
|
||||
attributes :id, :name, :description
|
||||
|
||||
belongs_to :author
|
||||
end
|
||||
belongs_to :author
|
||||
end
|
||||
|
||||
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)
|
||||
@role_hash = FragmentCache.new(RoleSerializer.adapter.new(@role_serializer), @role_serializer, {})
|
||||
@spam_hash = FragmentCache.new(Spam::UnrelatedLinkSerializer.adapter.new(@spam_serializer), @spam_serializer, {})
|
||||
end
|
||||
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)
|
||||
@role_hash = FragmentCache.new(::ActiveModelSerializers::Adapter.configured_adapter.new(@role_serializer), @role_serializer, {})
|
||||
@spam_hash = FragmentCache.new(::ActiveModelSerializers::Adapter.configured_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_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
|
||||
def test_fragment_fetch_with_namespaced_object
|
||||
expected_result = {
|
||||
id: @spam.id
|
||||
}
|
||||
assert_equal(@spam_hash.fetch, expected_result)
|
||||
end
|
||||
|
||||
def test_fragment_fetch_with_type_override
|
||||
serialization = serializable(Role.new(name: 'Another Author'), serializer: TypedRoleSerializer, adapter: :json_api).serializable_hash
|
||||
assert_equal(TypedRoleSerializer._type, serialization.fetch(:data).fetch(:type))
|
||||
end
|
||||
def test_fragment_fetch_with_type_override
|
||||
serialization = serializable(Role.new(name: 'Another Author'), serializer: TypedRoleSerializer, adapter: :json_api).serializable_hash
|
||||
assert_equal(TypedRoleSerializer._type, serialization.fetch(:data).fetch(:type))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,45 +1,43 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class Json
|
||||
class BelongsToTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
@post = Post.new(id: 42, title: 'New Post', body: 'Body')
|
||||
@anonymous_post = Post.new(id: 43, title: 'Hello!!', body: 'Hello, world!!')
|
||||
@comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@post.comments = [@comment]
|
||||
@anonymous_post.comments = []
|
||||
@comment.post = @post
|
||||
@comment.author = nil
|
||||
@anonymous_post.author = nil
|
||||
@blog = Blog.new(id: 1, name: 'My Blog!!')
|
||||
@post.blog = @blog
|
||||
@anonymous_post.blog = nil
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class Json
|
||||
class BelongsToTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
@post = Post.new(id: 42, title: 'New Post', body: 'Body')
|
||||
@anonymous_post = Post.new(id: 43, title: 'Hello!!', body: 'Hello, world!!')
|
||||
@comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@post.comments = [@comment]
|
||||
@anonymous_post.comments = []
|
||||
@comment.post = @post
|
||||
@comment.author = nil
|
||||
@anonymous_post.author = nil
|
||||
@blog = Blog.new(id: 1, name: 'My Blog!!')
|
||||
@post.blog = @blog
|
||||
@anonymous_post.blog = nil
|
||||
|
||||
@serializer = CommentSerializer.new(@comment)
|
||||
@adapter = ActiveModel::Serializer::Adapter::Json.new(@serializer)
|
||||
ActionController::Base.cache_store.clear
|
||||
end
|
||||
@serializer = CommentSerializer.new(@comment)
|
||||
@adapter = ActiveModelSerializers::Adapter::Json.new(@serializer)
|
||||
ActionController::Base.cache_store.clear
|
||||
end
|
||||
|
||||
def test_includes_post
|
||||
assert_equal({ id: 42, title: 'New Post', body: 'Body' }, @adapter.serializable_hash[:comment][:post])
|
||||
end
|
||||
def test_includes_post
|
||||
assert_equal({ id: 42, title: 'New Post', body: 'Body' }, @adapter.serializable_hash[:comment][:post])
|
||||
end
|
||||
|
||||
def test_include_nil_author
|
||||
serializer = PostSerializer.new(@anonymous_post)
|
||||
adapter = ActiveModel::Serializer::Adapter::Json.new(serializer)
|
||||
def test_include_nil_author
|
||||
serializer = PostSerializer.new(@anonymous_post)
|
||||
adapter = ActiveModelSerializers::Adapter::Json.new(serializer)
|
||||
|
||||
assert_equal({ post: { title: 'Hello!!', body: 'Hello, world!!', id: 43, comments: [], blog: { id: 999, name: 'Custom blog' }, author: nil } }, adapter.serializable_hash)
|
||||
end
|
||||
assert_equal({ post: { title: 'Hello!!', body: 'Hello, world!!', id: 43, comments: [], blog: { id: 999, name: 'Custom blog' }, author: nil } }, adapter.serializable_hash)
|
||||
end
|
||||
|
||||
def test_include_nil_author_with_specified_serializer
|
||||
serializer = PostPreviewSerializer.new(@anonymous_post)
|
||||
adapter = ActiveModel::Serializer::Adapter::Json.new(serializer)
|
||||
def test_include_nil_author_with_specified_serializer
|
||||
serializer = PostPreviewSerializer.new(@anonymous_post)
|
||||
adapter = ActiveModelSerializers::Adapter::Json.new(serializer)
|
||||
|
||||
assert_equal({ post: { title: 'Hello!!', body: 'Hello, world!!', id: 43, comments: [], author: nil } }, adapter.serializable_hash)
|
||||
end
|
||||
assert_equal({ post: { title: 'Hello!!', body: 'Hello, world!!', id: 43, comments: [], author: nil } }, adapter.serializable_hash)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,90 +1,88 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class Json
|
||||
class Collection < ActiveSupport::TestCase
|
||||
def setup
|
||||
@author = Author.new(id: 1, name: 'Steve K.')
|
||||
@first_post = Post.new(id: 1, title: 'Hello!!', body: 'Hello, world!!')
|
||||
@second_post = Post.new(id: 2, title: 'New Post', body: 'Body')
|
||||
@first_post.comments = []
|
||||
@second_post.comments = []
|
||||
@first_post.author = @author
|
||||
@second_post.author = @author
|
||||
@blog = Blog.new(id: 1, name: 'My Blog!!')
|
||||
@first_post.blog = @blog
|
||||
@second_post.blog = nil
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class Json
|
||||
class Collection < ActiveSupport::TestCase
|
||||
def setup
|
||||
@author = Author.new(id: 1, name: 'Steve K.')
|
||||
@first_post = Post.new(id: 1, title: 'Hello!!', body: 'Hello, world!!')
|
||||
@second_post = Post.new(id: 2, title: 'New Post', body: 'Body')
|
||||
@first_post.comments = []
|
||||
@second_post.comments = []
|
||||
@first_post.author = @author
|
||||
@second_post.author = @author
|
||||
@blog = Blog.new(id: 1, name: 'My Blog!!')
|
||||
@first_post.blog = @blog
|
||||
@second_post.blog = nil
|
||||
|
||||
ActionController::Base.cache_store.clear
|
||||
end
|
||||
ActionController::Base.cache_store.clear
|
||||
end
|
||||
|
||||
def test_with_serializer_option
|
||||
@blog.special_attribute = 'Special'
|
||||
@blog.articles = [@first_post, @second_post]
|
||||
serializer = CollectionSerializer.new([@blog], serializer: CustomBlogSerializer)
|
||||
adapter = ActiveModel::Serializer::Adapter::Json.new(serializer)
|
||||
def test_with_serializer_option
|
||||
@blog.special_attribute = 'Special'
|
||||
@blog.articles = [@first_post, @second_post]
|
||||
serializer = ActiveModel::Serializer::CollectionSerializer.new([@blog], serializer: CustomBlogSerializer)
|
||||
adapter = ActiveModelSerializers::Adapter::Json.new(serializer)
|
||||
|
||||
expected = { blogs: [{
|
||||
expected = { blogs: [{
|
||||
id: 1,
|
||||
special_attribute: 'Special',
|
||||
articles: [{ id: 1, title: 'Hello!!', body: 'Hello, world!!' }, { id: 2, title: 'New Post', body: 'Body' }]
|
||||
}] }
|
||||
assert_equal expected, adapter.serializable_hash
|
||||
end
|
||||
|
||||
def test_include_multiple_posts
|
||||
serializer = ActiveModel::Serializer::CollectionSerializer.new([@first_post, @second_post])
|
||||
adapter = ActiveModelSerializers::Adapter::Json.new(serializer)
|
||||
|
||||
expected = { posts: [{
|
||||
title: 'Hello!!',
|
||||
body: 'Hello, world!!',
|
||||
id: 1,
|
||||
comments: [],
|
||||
author: {
|
||||
id: 1,
|
||||
special_attribute: 'Special',
|
||||
articles: [{ id: 1, title: 'Hello!!', body: 'Hello, world!!' }, { id: 2, title: 'New Post', body: 'Body' }]
|
||||
}] }
|
||||
assert_equal expected, adapter.serializable_hash
|
||||
end
|
||||
|
||||
def test_include_multiple_posts
|
||||
serializer = CollectionSerializer.new([@first_post, @second_post])
|
||||
adapter = ActiveModel::Serializer::Adapter::Json.new(serializer)
|
||||
|
||||
expected = { posts: [{
|
||||
title: 'Hello!!',
|
||||
body: 'Hello, world!!',
|
||||
name: 'Steve K.'
|
||||
},
|
||||
blog: {
|
||||
id: 999,
|
||||
name: 'Custom blog'
|
||||
}
|
||||
}, {
|
||||
title: 'New Post',
|
||||
body: 'Body',
|
||||
id: 2,
|
||||
comments: [],
|
||||
author: {
|
||||
id: 1,
|
||||
comments: [],
|
||||
author: {
|
||||
id: 1,
|
||||
name: 'Steve K.'
|
||||
},
|
||||
blog: {
|
||||
id: 999,
|
||||
name: 'Custom blog'
|
||||
}
|
||||
}, {
|
||||
title: 'New Post',
|
||||
body: 'Body',
|
||||
id: 2,
|
||||
comments: [],
|
||||
author: {
|
||||
id: 1,
|
||||
name: 'Steve K.'
|
||||
},
|
||||
blog: {
|
||||
id: 999,
|
||||
name: 'Custom blog'
|
||||
}
|
||||
}] }
|
||||
assert_equal expected, adapter.serializable_hash
|
||||
end
|
||||
name: 'Steve K.'
|
||||
},
|
||||
blog: {
|
||||
id: 999,
|
||||
name: 'Custom blog'
|
||||
}
|
||||
}] }
|
||||
assert_equal expected, adapter.serializable_hash
|
||||
end
|
||||
|
||||
def test_root_is_underscored
|
||||
virtual_value = VirtualValue.new(id: 1)
|
||||
serializer = CollectionSerializer.new([virtual_value])
|
||||
adapter = ActiveModel::Serializer::Adapter::Json.new(serializer)
|
||||
def test_root_is_underscored
|
||||
virtual_value = VirtualValue.new(id: 1)
|
||||
serializer = ActiveModel::Serializer::CollectionSerializer.new([virtual_value])
|
||||
adapter = ActiveModelSerializers::Adapter::Json.new(serializer)
|
||||
|
||||
assert_equal 1, adapter.serializable_hash[:virtual_values].length
|
||||
end
|
||||
assert_equal 1, adapter.serializable_hash[:virtual_values].length
|
||||
end
|
||||
|
||||
def test_include_option
|
||||
serializer = CollectionSerializer.new([@first_post, @second_post])
|
||||
adapter = ActiveModel::Serializer::Adapter::Json.new(serializer, include: '')
|
||||
actual = adapter.serializable_hash
|
||||
expected = { posts: [{ id: 1, title: 'Hello!!', body: 'Hello, world!!' },
|
||||
{ id: 2, title: 'New Post', body: 'Body' }] }
|
||||
def test_include_option
|
||||
serializer = ActiveModel::Serializer::CollectionSerializer.new([@first_post, @second_post])
|
||||
adapter = ActiveModelSerializers::Adapter::Json.new(serializer, include: '')
|
||||
actual = adapter.serializable_hash
|
||||
expected = { posts: [{ id: 1, title: 'Hello!!', body: 'Hello, world!!' },
|
||||
{ id: 2, title: 'New Post', body: 'Body' }] }
|
||||
|
||||
assert_equal(expected, actual)
|
||||
end
|
||||
assert_equal(expected, actual)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,45 +1,43 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class Json
|
||||
class HasManyTestTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
ActionController::Base.cache_store.clear
|
||||
@author = Author.new(id: 1, name: 'Steve K.')
|
||||
@post = Post.new(id: 42, title: 'New Post', body: 'Body')
|
||||
@first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
|
||||
@post.comments = [@first_comment, @second_comment]
|
||||
@post.author = @author
|
||||
@first_comment.post = @post
|
||||
@second_comment.post = @post
|
||||
@blog = Blog.new(id: 1, name: 'My Blog!!')
|
||||
@post.blog = @blog
|
||||
@tag = Tag.new(id: 1, name: '#hash_tag')
|
||||
@post.tags = [@tag]
|
||||
end
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class Json
|
||||
class HasManyTestTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
ActionController::Base.cache_store.clear
|
||||
@author = Author.new(id: 1, name: 'Steve K.')
|
||||
@post = Post.new(id: 42, title: 'New Post', body: 'Body')
|
||||
@first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
|
||||
@post.comments = [@first_comment, @second_comment]
|
||||
@post.author = @author
|
||||
@first_comment.post = @post
|
||||
@second_comment.post = @post
|
||||
@blog = Blog.new(id: 1, name: 'My Blog!!')
|
||||
@post.blog = @blog
|
||||
@tag = Tag.new(id: 1, name: '#hash_tag')
|
||||
@post.tags = [@tag]
|
||||
end
|
||||
|
||||
def test_has_many
|
||||
serializer = PostSerializer.new(@post)
|
||||
adapter = ActiveModel::Serializer::Adapter::Json.new(serializer)
|
||||
assert_equal([
|
||||
{ id: 1, body: 'ZOMG A COMMENT' },
|
||||
{ id: 2, body: 'ZOMG ANOTHER COMMENT' }
|
||||
], adapter.serializable_hash[:post][:comments])
|
||||
end
|
||||
def test_has_many
|
||||
serializer = PostSerializer.new(@post)
|
||||
adapter = ActiveModelSerializers::Adapter::Json.new(serializer)
|
||||
assert_equal([
|
||||
{ id: 1, body: 'ZOMG A COMMENT' },
|
||||
{ id: 2, body: 'ZOMG ANOTHER COMMENT' }
|
||||
], adapter.serializable_hash[:post][:comments])
|
||||
end
|
||||
|
||||
def test_has_many_with_no_serializer
|
||||
serializer = PostWithTagsSerializer.new(@post)
|
||||
adapter = ActiveModel::Serializer::Adapter::Json.new(serializer)
|
||||
assert_equal({
|
||||
id: 42,
|
||||
tags: [
|
||||
{ 'id' => 1, 'name' => '#hash_tag' }
|
||||
]
|
||||
}.to_json, adapter.serializable_hash[:post].to_json)
|
||||
end
|
||||
def test_has_many_with_no_serializer
|
||||
serializer = PostWithTagsSerializer.new(@post)
|
||||
adapter = ActiveModelSerializers::Adapter::Json.new(serializer)
|
||||
assert_equal({
|
||||
id: 42,
|
||||
tags: [
|
||||
{ 'id' => 1, 'name' => '#hash_tag' }
|
||||
]
|
||||
}.to_json, adapter.serializable_hash[:post].to_json)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,155 +1,153 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class BelongsToTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
@author = Author.new(id: 1, name: 'Steve K.')
|
||||
@author.bio = nil
|
||||
@author.roles = []
|
||||
@blog = Blog.new(id: 23, name: 'AMS Blog')
|
||||
@post = Post.new(id: 42, title: 'New Post', body: 'Body')
|
||||
@anonymous_post = Post.new(id: 43, title: 'Hello!!', body: 'Hello, world!!')
|
||||
@comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@post.comments = [@comment]
|
||||
@post.blog = @blog
|
||||
@anonymous_post.comments = []
|
||||
@anonymous_post.blog = nil
|
||||
@comment.post = @post
|
||||
@comment.author = nil
|
||||
@post.author = @author
|
||||
@anonymous_post.author = nil
|
||||
@blog = Blog.new(id: 1, name: 'My Blog!!')
|
||||
@blog.writer = @author
|
||||
@blog.articles = [@post, @anonymous_post]
|
||||
@author.posts = []
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class BelongsToTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
@author = Author.new(id: 1, name: 'Steve K.')
|
||||
@author.bio = nil
|
||||
@author.roles = []
|
||||
@blog = Blog.new(id: 23, name: 'AMS Blog')
|
||||
@post = Post.new(id: 42, title: 'New Post', body: 'Body')
|
||||
@anonymous_post = Post.new(id: 43, title: 'Hello!!', body: 'Hello, world!!')
|
||||
@comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@post.comments = [@comment]
|
||||
@post.blog = @blog
|
||||
@anonymous_post.comments = []
|
||||
@anonymous_post.blog = nil
|
||||
@comment.post = @post
|
||||
@comment.author = nil
|
||||
@post.author = @author
|
||||
@anonymous_post.author = nil
|
||||
@blog = Blog.new(id: 1, name: 'My Blog!!')
|
||||
@blog.writer = @author
|
||||
@blog.articles = [@post, @anonymous_post]
|
||||
@author.posts = []
|
||||
|
||||
@serializer = CommentSerializer.new(@comment)
|
||||
@adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer)
|
||||
ActionController::Base.cache_store.clear
|
||||
end
|
||||
@serializer = CommentSerializer.new(@comment)
|
||||
@adapter = ActiveModelSerializers::Adapter::JsonApi.new(@serializer)
|
||||
ActionController::Base.cache_store.clear
|
||||
end
|
||||
|
||||
def test_includes_post_id
|
||||
expected = { data: { type: 'posts', id: '42' } }
|
||||
def test_includes_post_id
|
||||
expected = { data: { type: 'posts', id: '42' } }
|
||||
|
||||
assert_equal(expected, @adapter.serializable_hash[:data][:relationships][:post])
|
||||
end
|
||||
assert_equal(expected, @adapter.serializable_hash[:data][:relationships][:post])
|
||||
end
|
||||
|
||||
def test_includes_linked_post
|
||||
@adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: [:post])
|
||||
expected = [{
|
||||
def test_includes_linked_post
|
||||
@adapter = ActiveModelSerializers::Adapter::JsonApi.new(@serializer, include: [:post])
|
||||
expected = [{
|
||||
id: '42',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'New Post',
|
||||
body: 'Body',
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [{ type: 'comments', id: '1' }] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
}]
|
||||
assert_equal expected, @adapter.serializable_hash[:included]
|
||||
end
|
||||
|
||||
def test_limiting_linked_post_fields
|
||||
@adapter = ActiveModelSerializers::Adapter::JsonApi.new(@serializer, include: [:post], fields: { post: [:title, :comments, :blog, :author] })
|
||||
expected = [{
|
||||
id: '42',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'New Post'
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [{ type: 'comments', id: '1' }] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
}]
|
||||
assert_equal expected, @adapter.serializable_hash[:included]
|
||||
end
|
||||
|
||||
def test_include_nil_author
|
||||
serializer = PostSerializer.new(@anonymous_post)
|
||||
adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
|
||||
|
||||
assert_equal({ comments: { data: [] }, blog: { data: { type: 'blogs', id: '999' } }, author: { data: nil } }, adapter.serializable_hash[:data][:relationships])
|
||||
end
|
||||
|
||||
def test_include_type_for_association_when_different_than_name
|
||||
serializer = BlogSerializer.new(@blog)
|
||||
adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
|
||||
relationships = adapter.serializable_hash[:data][:relationships]
|
||||
expected = {
|
||||
writer: {
|
||||
data: {
|
||||
type: 'authors',
|
||||
id: '1'
|
||||
}
|
||||
},
|
||||
articles: {
|
||||
data: [
|
||||
{
|
||||
type: 'posts',
|
||||
id: '42'
|
||||
},
|
||||
{
|
||||
type: 'posts',
|
||||
id: '43'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
assert_equal expected, relationships
|
||||
end
|
||||
|
||||
def test_include_linked_resources_with_type_name
|
||||
serializer = BlogSerializer.new(@blog)
|
||||
adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer, include: [:writer, :articles])
|
||||
linked = adapter.serializable_hash[:included]
|
||||
expected = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'authors',
|
||||
attributes: {
|
||||
name: 'Steve K.'
|
||||
},
|
||||
relationships: {
|
||||
posts: { data: [] },
|
||||
roles: { data: [] },
|
||||
bio: { data: nil }
|
||||
}
|
||||
}, {
|
||||
id: '42',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'New Post',
|
||||
body: 'Body',
|
||||
body: 'Body'
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [{ type: 'comments', id: '1' }] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
}]
|
||||
assert_equal expected, @adapter.serializable_hash[:included]
|
||||
end
|
||||
|
||||
def test_limiting_linked_post_fields
|
||||
@adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: [:post], fields: { post: [:title, :comments, :blog, :author] })
|
||||
expected = [{
|
||||
id: '42',
|
||||
}, {
|
||||
id: '43',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'New Post'
|
||||
title: 'Hello!!',
|
||||
body: 'Hello, world!!'
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [{ type: 'comments', id: '1' }] },
|
||||
comments: { data: [] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
}]
|
||||
assert_equal expected, @adapter.serializable_hash[:included]
|
||||
end
|
||||
|
||||
def test_include_nil_author
|
||||
serializer = PostSerializer.new(@anonymous_post)
|
||||
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer)
|
||||
|
||||
assert_equal({ comments: { data: [] }, blog: { data: { type: 'blogs', id: '999' } }, author: { data: nil } }, adapter.serializable_hash[:data][:relationships])
|
||||
end
|
||||
|
||||
def test_include_type_for_association_when_different_than_name
|
||||
serializer = BlogSerializer.new(@blog)
|
||||
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer)
|
||||
relationships = adapter.serializable_hash[:data][:relationships]
|
||||
expected = {
|
||||
writer: {
|
||||
data: {
|
||||
type: 'authors',
|
||||
id: '1'
|
||||
}
|
||||
},
|
||||
articles: {
|
||||
data: [
|
||||
{
|
||||
type: 'posts',
|
||||
id: '42'
|
||||
},
|
||||
{
|
||||
type: 'posts',
|
||||
id: '43'
|
||||
}
|
||||
]
|
||||
author: { data: nil }
|
||||
}
|
||||
}
|
||||
assert_equal expected, relationships
|
||||
end
|
||||
|
||||
def test_include_linked_resources_with_type_name
|
||||
serializer = BlogSerializer.new(@blog)
|
||||
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer, include: [:writer, :articles])
|
||||
linked = adapter.serializable_hash[:included]
|
||||
expected = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'authors',
|
||||
attributes: {
|
||||
name: 'Steve K.'
|
||||
},
|
||||
relationships: {
|
||||
posts: { data: [] },
|
||||
roles: { data: [] },
|
||||
bio: { data: nil }
|
||||
}
|
||||
}, {
|
||||
id: '42',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'New Post',
|
||||
body: 'Body'
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [{ type: 'comments', id: '1' }] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
}, {
|
||||
id: '43',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'Hello!!',
|
||||
body: 'Hello, world!!'
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: nil }
|
||||
}
|
||||
}
|
||||
]
|
||||
assert_equal expected, linked
|
||||
end
|
||||
]
|
||||
assert_equal expected, linked
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,95 +1,93 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class CollectionTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
@author = Author.new(id: 1, name: 'Steve K.')
|
||||
@author.bio = nil
|
||||
@blog = Blog.new(id: 23, name: 'AMS Blog')
|
||||
@first_post = Post.new(id: 1, title: 'Hello!!', body: 'Hello, world!!')
|
||||
@second_post = Post.new(id: 2, title: 'New Post', body: 'Body')
|
||||
@first_post.comments = []
|
||||
@second_post.comments = []
|
||||
@first_post.blog = @blog
|
||||
@second_post.blog = nil
|
||||
@first_post.author = @author
|
||||
@second_post.author = @author
|
||||
@author.posts = [@first_post, @second_post]
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class CollectionTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
@author = Author.new(id: 1, name: 'Steve K.')
|
||||
@author.bio = nil
|
||||
@blog = Blog.new(id: 23, name: 'AMS Blog')
|
||||
@first_post = Post.new(id: 1, title: 'Hello!!', body: 'Hello, world!!')
|
||||
@second_post = Post.new(id: 2, title: 'New Post', body: 'Body')
|
||||
@first_post.comments = []
|
||||
@second_post.comments = []
|
||||
@first_post.blog = @blog
|
||||
@second_post.blog = nil
|
||||
@first_post.author = @author
|
||||
@second_post.author = @author
|
||||
@author.posts = [@first_post, @second_post]
|
||||
|
||||
@serializer = CollectionSerializer.new([@first_post, @second_post])
|
||||
@adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer)
|
||||
ActionController::Base.cache_store.clear
|
||||
end
|
||||
@serializer = ActiveModel::Serializer::CollectionSerializer.new([@first_post, @second_post])
|
||||
@adapter = ActiveModelSerializers::Adapter::JsonApi.new(@serializer)
|
||||
ActionController::Base.cache_store.clear
|
||||
end
|
||||
|
||||
def test_include_multiple_posts
|
||||
expected = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'Hello!!',
|
||||
body: 'Hello, world!!'
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
def test_include_multiple_posts
|
||||
expected = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'Hello!!',
|
||||
body: 'Hello, world!!'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'New Post',
|
||||
body: 'Body'
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
relationships: {
|
||||
comments: { data: [] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
]
|
||||
|
||||
assert_equal(expected, @adapter.serializable_hash[:data])
|
||||
end
|
||||
|
||||
def test_limiting_fields
|
||||
actual = ActiveModel::SerializableResource.new(
|
||||
[@first_post, @second_post], adapter: :json_api,
|
||||
fields: { posts: %w(title comments blog author) })
|
||||
.serializable_hash
|
||||
expected = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'Hello!!'
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'New Post',
|
||||
body: 'Body'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'New Post'
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
relationships: {
|
||||
comments: { data: [] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
]
|
||||
assert_equal(expected, actual[:data])
|
||||
end
|
||||
}
|
||||
]
|
||||
|
||||
assert_equal(expected, @adapter.serializable_hash[:data])
|
||||
end
|
||||
|
||||
def test_limiting_fields
|
||||
actual = ActiveModel::SerializableResource.new(
|
||||
[@first_post, @second_post], adapter: :json_api,
|
||||
fields: { posts: %w(title comments blog author) })
|
||||
.serializable_hash
|
||||
expected = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'Hello!!'
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'New Post'
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
}
|
||||
]
|
||||
assert_equal(expected, actual[:data])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,87 +1,85 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class FieldsTest < ActiveSupport::TestCase
|
||||
Post = Class.new(::Model)
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
type 'posts'
|
||||
attributes :title, :body
|
||||
belongs_to :author
|
||||
has_many :comments
|
||||
end
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class FieldsTest < ActiveSupport::TestCase
|
||||
Post = Class.new(::Model)
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
type 'posts'
|
||||
attributes :title, :body
|
||||
belongs_to :author
|
||||
has_many :comments
|
||||
end
|
||||
|
||||
Author = Class.new(::Model)
|
||||
class AuthorSerializer < ActiveModel::Serializer
|
||||
type 'authors'
|
||||
attributes :name, :birthday
|
||||
end
|
||||
Author = Class.new(::Model)
|
||||
class AuthorSerializer < ActiveModel::Serializer
|
||||
type 'authors'
|
||||
attributes :name, :birthday
|
||||
end
|
||||
|
||||
Comment = Class.new(::Model)
|
||||
class CommentSerializer < ActiveModel::Serializer
|
||||
type 'comments'
|
||||
attributes :body
|
||||
belongs_to :author
|
||||
end
|
||||
Comment = Class.new(::Model)
|
||||
class CommentSerializer < ActiveModel::Serializer
|
||||
type 'comments'
|
||||
attributes :body
|
||||
belongs_to :author
|
||||
end
|
||||
|
||||
def setup
|
||||
@author = Author.new(id: 1, name: 'Lucas', birthday: '10.01.1990')
|
||||
@comment1 = Comment.new(id: 7, body: 'cool', author: @author)
|
||||
@comment2 = Comment.new(id: 12, body: 'awesome', author: @author)
|
||||
@post = Post.new(id: 1337, title: 'Title 1', body: 'Body 1',
|
||||
author: @author, comments: [@comment1, @comment2])
|
||||
@comment1.post = @post
|
||||
@comment2.post = @post
|
||||
end
|
||||
def setup
|
||||
@author = Author.new(id: 1, name: 'Lucas', birthday: '10.01.1990')
|
||||
@comment1 = Comment.new(id: 7, body: 'cool', author: @author)
|
||||
@comment2 = Comment.new(id: 12, body: 'awesome', author: @author)
|
||||
@post = Post.new(id: 1337, title: 'Title 1', body: 'Body 1',
|
||||
author: @author, comments: [@comment1, @comment2])
|
||||
@comment1.post = @post
|
||||
@comment2.post = @post
|
||||
end
|
||||
|
||||
def test_fields_attributes
|
||||
fields = { posts: [:title] }
|
||||
hash = serializable(@post, adapter: :json_api, fields: fields).serializable_hash
|
||||
expected = {
|
||||
title: 'Title 1'
|
||||
}
|
||||
def test_fields_attributes
|
||||
fields = { posts: [:title] }
|
||||
hash = serializable(@post, adapter: :json_api, fields: fields).serializable_hash
|
||||
expected = {
|
||||
title: 'Title 1'
|
||||
}
|
||||
|
||||
assert_equal(expected, hash[:data][:attributes])
|
||||
end
|
||||
assert_equal(expected, hash[:data][:attributes])
|
||||
end
|
||||
|
||||
def test_fields_relationships
|
||||
fields = { posts: [:author] }
|
||||
hash = serializable(@post, adapter: :json_api, fields: fields).serializable_hash
|
||||
expected = {
|
||||
author: {
|
||||
data: {
|
||||
type: 'authors',
|
||||
id: '1'
|
||||
}
|
||||
def test_fields_relationships
|
||||
fields = { posts: [:author] }
|
||||
hash = serializable(@post, adapter: :json_api, fields: fields).serializable_hash
|
||||
expected = {
|
||||
author: {
|
||||
data: {
|
||||
type: 'authors',
|
||||
id: '1'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert_equal(expected, hash[:data][:relationships])
|
||||
end
|
||||
assert_equal(expected, hash[:data][:relationships])
|
||||
end
|
||||
|
||||
def test_fields_included
|
||||
fields = { posts: [:author], comments: [:body] }
|
||||
hash = serializable(@post, adapter: :json_api, fields: fields, include: 'comments').serializable_hash
|
||||
expected = [
|
||||
{
|
||||
type: 'comments',
|
||||
id: '7',
|
||||
attributes: {
|
||||
body: 'cool'
|
||||
}
|
||||
}, {
|
||||
type: 'comments',
|
||||
id: '12',
|
||||
attributes: {
|
||||
body: 'awesome'
|
||||
}
|
||||
def test_fields_included
|
||||
fields = { posts: [:author], comments: [:body] }
|
||||
hash = serializable(@post, adapter: :json_api, fields: fields, include: 'comments').serializable_hash
|
||||
expected = [
|
||||
{
|
||||
type: 'comments',
|
||||
id: '7',
|
||||
attributes: {
|
||||
body: 'cool'
|
||||
}
|
||||
]
|
||||
}, {
|
||||
type: 'comments',
|
||||
id: '12',
|
||||
attributes: {
|
||||
body: 'awesome'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
assert_equal(expected, hash[:included])
|
||||
end
|
||||
assert_equal(expected, hash[:included])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,43 +1,41 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class HasManyEmbedIdsTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
@author = Author.new(name: 'Steve K.')
|
||||
@author.bio = nil
|
||||
@author.roles = nil
|
||||
@first_post = Post.new(id: 1, title: 'Hello!!', body: 'Hello, world!!')
|
||||
@second_post = Post.new(id: 2, title: 'New Post', body: 'Body')
|
||||
@author.posts = [@first_post, @second_post]
|
||||
@first_post.author = @author
|
||||
@second_post.author = @author
|
||||
@first_post.comments = []
|
||||
@second_post.comments = []
|
||||
@blog = Blog.new(id: 23, name: 'AMS Blog')
|
||||
@first_post.blog = @blog
|
||||
@second_post.blog = nil
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class HasManyEmbedIdsTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
@author = Author.new(name: 'Steve K.')
|
||||
@author.bio = nil
|
||||
@author.roles = nil
|
||||
@first_post = Post.new(id: 1, title: 'Hello!!', body: 'Hello, world!!')
|
||||
@second_post = Post.new(id: 2, title: 'New Post', body: 'Body')
|
||||
@author.posts = [@first_post, @second_post]
|
||||
@first_post.author = @author
|
||||
@second_post.author = @author
|
||||
@first_post.comments = []
|
||||
@second_post.comments = []
|
||||
@blog = Blog.new(id: 23, name: 'AMS Blog')
|
||||
@first_post.blog = @blog
|
||||
@second_post.blog = nil
|
||||
|
||||
@serializer = AuthorSerializer.new(@author)
|
||||
@adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer)
|
||||
end
|
||||
@serializer = AuthorSerializer.new(@author)
|
||||
@adapter = ActiveModelSerializers::Adapter::JsonApi.new(@serializer)
|
||||
end
|
||||
|
||||
def test_includes_comment_ids
|
||||
expected = {
|
||||
data: [
|
||||
{ type: 'posts', id: '1' },
|
||||
{ type: 'posts', id: '2' }
|
||||
]
|
||||
}
|
||||
def test_includes_comment_ids
|
||||
expected = {
|
||||
data: [
|
||||
{ type: 'posts', id: '1' },
|
||||
{ type: 'posts', id: '2' }
|
||||
]
|
||||
}
|
||||
|
||||
assert_equal(expected, @adapter.serializable_hash[:data][:relationships][:posts])
|
||||
end
|
||||
assert_equal(expected, @adapter.serializable_hash[:data][:relationships][:posts])
|
||||
end
|
||||
|
||||
def test_no_includes_linked_comments
|
||||
assert_nil @adapter.serializable_hash[:linked]
|
||||
end
|
||||
def test_no_includes_linked_comments
|
||||
assert_nil @adapter.serializable_hash[:linked]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,96 +1,94 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class JsonApi
|
||||
# Test 'has_many :assocs, serializer: AssocXSerializer'
|
||||
class HasManyExplicitSerializerTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
@post = Post.new(title: 'New Post', body: 'Body')
|
||||
@author = Author.new(name: 'Jane Blogger')
|
||||
@author.posts = [@post]
|
||||
@post.author = @author
|
||||
@first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
|
||||
@post.comments = [@first_comment, @second_comment]
|
||||
@first_comment.post = @post
|
||||
@first_comment.author = nil
|
||||
@second_comment.post = @post
|
||||
@second_comment.author = nil
|
||||
@blog = Blog.new(id: 23, name: 'AMS Blog')
|
||||
@post.blog = @blog
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi
|
||||
# Test 'has_many :assocs, serializer: AssocXSerializer'
|
||||
class HasManyExplicitSerializerTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
@post = Post.new(title: 'New Post', body: 'Body')
|
||||
@author = Author.new(name: 'Jane Blogger')
|
||||
@author.posts = [@post]
|
||||
@post.author = @author
|
||||
@first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
|
||||
@post.comments = [@first_comment, @second_comment]
|
||||
@first_comment.post = @post
|
||||
@first_comment.author = nil
|
||||
@second_comment.post = @post
|
||||
@second_comment.author = nil
|
||||
@blog = Blog.new(id: 23, name: 'AMS Blog')
|
||||
@post.blog = @blog
|
||||
|
||||
@serializer = PostPreviewSerializer.new(@post)
|
||||
@adapter = ActiveModel::Serializer::Adapter::JsonApi.new(
|
||||
@serializer,
|
||||
include: [:comments, :author]
|
||||
)
|
||||
end
|
||||
@serializer = PostPreviewSerializer.new(@post)
|
||||
@adapter = ActiveModelSerializers::Adapter::JsonApi.new(
|
||||
@serializer,
|
||||
include: [:comments, :author]
|
||||
)
|
||||
end
|
||||
|
||||
def test_includes_comment_ids
|
||||
expected = {
|
||||
data: [
|
||||
{ type: 'comments', id: '1' },
|
||||
{ type: 'comments', id: '2' }
|
||||
]
|
||||
}
|
||||
|
||||
assert_equal(expected, @adapter.serializable_hash[:data][:relationships][:comments])
|
||||
end
|
||||
|
||||
def test_includes_linked_data
|
||||
# If CommentPreviewSerializer is applied correctly the body text will not be present in the output
|
||||
expected = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'comments',
|
||||
relationships: {
|
||||
post: { data: { type: 'posts', id: @post.id.to_s } }
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'comments',
|
||||
relationships: {
|
||||
post: { data: { type: 'posts', id: @post.id.to_s } }
|
||||
}
|
||||
},
|
||||
{
|
||||
id: @author.id.to_s,
|
||||
type: 'authors',
|
||||
relationships: {
|
||||
posts: { data: [{ type: 'posts', id: @post.id.to_s }] }
|
||||
}
|
||||
}
|
||||
def test_includes_comment_ids
|
||||
expected = {
|
||||
data: [
|
||||
{ type: 'comments', id: '1' },
|
||||
{ type: 'comments', id: '2' }
|
||||
]
|
||||
}
|
||||
|
||||
assert_equal(expected, @adapter.serializable_hash[:included])
|
||||
end
|
||||
assert_equal(expected, @adapter.serializable_hash[:data][:relationships][:comments])
|
||||
end
|
||||
|
||||
def test_includes_author_id
|
||||
expected = {
|
||||
data: { type: 'authors', id: @author.id.to_s }
|
||||
def test_includes_linked_data
|
||||
# If CommentPreviewSerializer is applied correctly the body text will not be present in the output
|
||||
expected = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'comments',
|
||||
relationships: {
|
||||
post: { data: { type: 'posts', id: @post.id.to_s } }
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'comments',
|
||||
relationships: {
|
||||
post: { data: { type: 'posts', id: @post.id.to_s } }
|
||||
}
|
||||
},
|
||||
{
|
||||
id: @author.id.to_s,
|
||||
type: 'authors',
|
||||
relationships: {
|
||||
posts: { data: [{ type: 'posts', id: @post.id.to_s }] }
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
assert_equal(expected, @adapter.serializable_hash[:data][:relationships][:author])
|
||||
end
|
||||
assert_equal(expected, @adapter.serializable_hash[:included])
|
||||
end
|
||||
|
||||
def test_explicit_serializer_with_null_resource
|
||||
@post.author = nil
|
||||
def test_includes_author_id
|
||||
expected = {
|
||||
data: { type: 'authors', id: @author.id.to_s }
|
||||
}
|
||||
|
||||
expected = { data: nil }
|
||||
assert_equal(expected, @adapter.serializable_hash[:data][:relationships][:author])
|
||||
end
|
||||
|
||||
assert_equal(expected, @adapter.serializable_hash[:data][:relationships][:author])
|
||||
end
|
||||
def test_explicit_serializer_with_null_resource
|
||||
@post.author = nil
|
||||
|
||||
def test_explicit_serializer_with_null_collection
|
||||
@post.comments = []
|
||||
expected = { data: nil }
|
||||
|
||||
expected = { data: [] }
|
||||
assert_equal(expected, @adapter.serializable_hash[:data][:relationships][:author])
|
||||
end
|
||||
|
||||
assert_equal(expected, @adapter.serializable_hash[:data][:relationships][:comments])
|
||||
end
|
||||
def test_explicit_serializer_with_null_collection
|
||||
@post.comments = []
|
||||
|
||||
expected = { data: [] }
|
||||
|
||||
assert_equal(expected, @adapter.serializable_hash[:data][:relationships][:comments])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,143 +1,141 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class HasManyTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
ActionController::Base.cache_store.clear
|
||||
@author = Author.new(id: 1, name: 'Steve K.')
|
||||
@author.posts = []
|
||||
@author.bio = nil
|
||||
@post = Post.new(id: 1, title: 'New Post', body: 'Body')
|
||||
@post_without_comments = Post.new(id: 2, title: 'Second Post', body: 'Second')
|
||||
@first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@first_comment.author = nil
|
||||
@second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
|
||||
@second_comment.author = nil
|
||||
@post.comments = [@first_comment, @second_comment]
|
||||
@post_without_comments.comments = []
|
||||
@first_comment.post = @post
|
||||
@second_comment.post = @post
|
||||
@post.author = @author
|
||||
@post_without_comments.author = nil
|
||||
@blog = Blog.new(id: 1, name: 'My Blog!!')
|
||||
@blog.writer = @author
|
||||
@blog.articles = [@post]
|
||||
@post.blog = @blog
|
||||
@post_without_comments.blog = nil
|
||||
@tag = Tag.new(id: 1, name: '#hash_tag')
|
||||
@post.tags = [@tag]
|
||||
@serializer = PostSerializer.new(@post)
|
||||
@adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer)
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class HasManyTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
ActionController::Base.cache_store.clear
|
||||
@author = Author.new(id: 1, name: 'Steve K.')
|
||||
@author.posts = []
|
||||
@author.bio = nil
|
||||
@post = Post.new(id: 1, title: 'New Post', body: 'Body')
|
||||
@post_without_comments = Post.new(id: 2, title: 'Second Post', body: 'Second')
|
||||
@first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@first_comment.author = nil
|
||||
@second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
|
||||
@second_comment.author = nil
|
||||
@post.comments = [@first_comment, @second_comment]
|
||||
@post_without_comments.comments = []
|
||||
@first_comment.post = @post
|
||||
@second_comment.post = @post
|
||||
@post.author = @author
|
||||
@post_without_comments.author = nil
|
||||
@blog = Blog.new(id: 1, name: 'My Blog!!')
|
||||
@blog.writer = @author
|
||||
@blog.articles = [@post]
|
||||
@post.blog = @blog
|
||||
@post_without_comments.blog = nil
|
||||
@tag = Tag.new(id: 1, name: '#hash_tag')
|
||||
@post.tags = [@tag]
|
||||
@serializer = PostSerializer.new(@post)
|
||||
@adapter = ActiveModelSerializers::Adapter::JsonApi.new(@serializer)
|
||||
|
||||
@virtual_value = VirtualValue.new(id: 1)
|
||||
end
|
||||
@virtual_value = VirtualValue.new(id: 1)
|
||||
end
|
||||
|
||||
def test_includes_comment_ids
|
||||
expected = { data: [{ type: 'comments', id: '1' }, { type: 'comments', id: '2' }] }
|
||||
def test_includes_comment_ids
|
||||
expected = { data: [{ type: 'comments', id: '1' }, { type: 'comments', id: '2' }] }
|
||||
|
||||
assert_equal(expected, @adapter.serializable_hash[:data][:relationships][:comments])
|
||||
end
|
||||
assert_equal(expected, @adapter.serializable_hash[:data][:relationships][:comments])
|
||||
end
|
||||
|
||||
def test_includes_linked_comments
|
||||
@adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: [:comments])
|
||||
expected = [{
|
||||
id: '1',
|
||||
type: 'comments',
|
||||
attributes: {
|
||||
body: 'ZOMG A COMMENT'
|
||||
},
|
||||
relationships: {
|
||||
post: { data: { type: 'posts', id: '1' } },
|
||||
author: { data: nil }
|
||||
}
|
||||
}, {
|
||||
id: '2',
|
||||
type: 'comments',
|
||||
attributes: {
|
||||
body: 'ZOMG ANOTHER COMMENT'
|
||||
},
|
||||
relationships: {
|
||||
post: { data: { type: 'posts', id: '1' } },
|
||||
author: { data: nil }
|
||||
}
|
||||
}]
|
||||
assert_equal expected, @adapter.serializable_hash[:included]
|
||||
end
|
||||
|
||||
def test_limit_fields_of_linked_comments
|
||||
@adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: [:comments], fields: { comment: [:id, :post, :author] })
|
||||
expected = [{
|
||||
id: '1',
|
||||
type: 'comments',
|
||||
relationships: {
|
||||
post: { data: { type: 'posts', id: '1' } },
|
||||
author: { data: nil }
|
||||
}
|
||||
}, {
|
||||
id: '2',
|
||||
type: 'comments',
|
||||
relationships: {
|
||||
post: { data: { type: 'posts', id: '1' } },
|
||||
author: { data: nil }
|
||||
}
|
||||
}]
|
||||
assert_equal expected, @adapter.serializable_hash[:included]
|
||||
end
|
||||
|
||||
def test_no_include_linked_if_comments_is_empty
|
||||
serializer = PostSerializer.new(@post_without_comments)
|
||||
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer)
|
||||
|
||||
assert_nil adapter.serializable_hash[:linked]
|
||||
end
|
||||
|
||||
def test_include_type_for_association_when_different_than_name
|
||||
serializer = BlogSerializer.new(@blog)
|
||||
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer)
|
||||
actual = adapter.serializable_hash[:data][:relationships][:articles]
|
||||
|
||||
expected = {
|
||||
data: [{
|
||||
type: 'posts',
|
||||
id: '1'
|
||||
}]
|
||||
def test_includes_linked_comments
|
||||
@adapter = ActiveModelSerializers::Adapter::JsonApi.new(@serializer, include: [:comments])
|
||||
expected = [{
|
||||
id: '1',
|
||||
type: 'comments',
|
||||
attributes: {
|
||||
body: 'ZOMG A COMMENT'
|
||||
},
|
||||
relationships: {
|
||||
post: { data: { type: 'posts', id: '1' } },
|
||||
author: { data: nil }
|
||||
}
|
||||
assert_equal expected, actual
|
||||
end
|
||||
}, {
|
||||
id: '2',
|
||||
type: 'comments',
|
||||
attributes: {
|
||||
body: 'ZOMG ANOTHER COMMENT'
|
||||
},
|
||||
relationships: {
|
||||
post: { data: { type: 'posts', id: '1' } },
|
||||
author: { data: nil }
|
||||
}
|
||||
}]
|
||||
assert_equal expected, @adapter.serializable_hash[:included]
|
||||
end
|
||||
|
||||
def test_has_many_with_no_serializer
|
||||
serializer = PostWithTagsSerializer.new(@post)
|
||||
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer)
|
||||
def test_limit_fields_of_linked_comments
|
||||
@adapter = ActiveModelSerializers::Adapter::JsonApi.new(@serializer, include: [:comments], fields: { comment: [:id, :post, :author] })
|
||||
expected = [{
|
||||
id: '1',
|
||||
type: 'comments',
|
||||
relationships: {
|
||||
post: { data: { type: 'posts', id: '1' } },
|
||||
author: { data: nil }
|
||||
}
|
||||
}, {
|
||||
id: '2',
|
||||
type: 'comments',
|
||||
relationships: {
|
||||
post: { data: { type: 'posts', id: '1' } },
|
||||
author: { data: nil }
|
||||
}
|
||||
}]
|
||||
assert_equal expected, @adapter.serializable_hash[:included]
|
||||
end
|
||||
|
||||
assert_equal({
|
||||
data: {
|
||||
id: '1',
|
||||
type: 'posts',
|
||||
relationships: {
|
||||
tags: { data: [@tag.as_json] }
|
||||
}
|
||||
def test_no_include_linked_if_comments_is_empty
|
||||
serializer = PostSerializer.new(@post_without_comments)
|
||||
adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
|
||||
|
||||
assert_nil adapter.serializable_hash[:linked]
|
||||
end
|
||||
|
||||
def test_include_type_for_association_when_different_than_name
|
||||
serializer = BlogSerializer.new(@blog)
|
||||
adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
|
||||
actual = adapter.serializable_hash[:data][:relationships][:articles]
|
||||
|
||||
expected = {
|
||||
data: [{
|
||||
type: 'posts',
|
||||
id: '1'
|
||||
}]
|
||||
}
|
||||
assert_equal expected, actual
|
||||
end
|
||||
|
||||
def test_has_many_with_no_serializer
|
||||
serializer = PostWithTagsSerializer.new(@post)
|
||||
adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
|
||||
|
||||
assert_equal({
|
||||
data: {
|
||||
id: '1',
|
||||
type: 'posts',
|
||||
relationships: {
|
||||
tags: { data: [@tag.as_json] }
|
||||
}
|
||||
}, adapter.serializable_hash)
|
||||
end
|
||||
}
|
||||
}, adapter.serializable_hash)
|
||||
end
|
||||
|
||||
def test_has_many_with_virtual_value
|
||||
serializer = VirtualValueSerializer.new(@virtual_value)
|
||||
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer)
|
||||
def test_has_many_with_virtual_value
|
||||
serializer = VirtualValueSerializer.new(@virtual_value)
|
||||
adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
|
||||
|
||||
assert_equal({
|
||||
data: {
|
||||
id: '1',
|
||||
type: 'virtual_values',
|
||||
relationships: {
|
||||
maker: { data: { id: 1 } },
|
||||
reviews: { data: [{ id: 1 }, { id: 2 }] }
|
||||
}
|
||||
assert_equal({
|
||||
data: {
|
||||
id: '1',
|
||||
type: 'virtual_values',
|
||||
relationships: {
|
||||
maker: { data: { id: 1 } },
|
||||
reviews: { data: [{ id: 1 }, { id: 2 }] }
|
||||
}
|
||||
}, adapter.serializable_hash)
|
||||
end
|
||||
}
|
||||
}, adapter.serializable_hash)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,79 +1,77 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class HasOneTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
@author = Author.new(id: 1, name: 'Steve K.')
|
||||
@bio = Bio.new(id: 43, content: 'AMS Contributor')
|
||||
@author.bio = @bio
|
||||
@bio.author = @author
|
||||
@post = Post.new(id: 42, title: 'New Post', body: 'Body')
|
||||
@anonymous_post = Post.new(id: 43, title: 'Hello!!', body: 'Hello, world!!')
|
||||
@comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@post.comments = [@comment]
|
||||
@anonymous_post.comments = []
|
||||
@comment.post = @post
|
||||
@comment.author = nil
|
||||
@post.author = @author
|
||||
@anonymous_post.author = nil
|
||||
@blog = Blog.new(id: 1, name: 'My Blog!!')
|
||||
@blog.writer = @author
|
||||
@blog.articles = [@post, @anonymous_post]
|
||||
@author.posts = []
|
||||
@author.roles = []
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class HasOneTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
@author = Author.new(id: 1, name: 'Steve K.')
|
||||
@bio = Bio.new(id: 43, content: 'AMS Contributor')
|
||||
@author.bio = @bio
|
||||
@bio.author = @author
|
||||
@post = Post.new(id: 42, title: 'New Post', body: 'Body')
|
||||
@anonymous_post = Post.new(id: 43, title: 'Hello!!', body: 'Hello, world!!')
|
||||
@comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@post.comments = [@comment]
|
||||
@anonymous_post.comments = []
|
||||
@comment.post = @post
|
||||
@comment.author = nil
|
||||
@post.author = @author
|
||||
@anonymous_post.author = nil
|
||||
@blog = Blog.new(id: 1, name: 'My Blog!!')
|
||||
@blog.writer = @author
|
||||
@blog.articles = [@post, @anonymous_post]
|
||||
@author.posts = []
|
||||
@author.roles = []
|
||||
|
||||
@virtual_value = VirtualValue.new(id: 1)
|
||||
@virtual_value = VirtualValue.new(id: 1)
|
||||
|
||||
@serializer = AuthorSerializer.new(@author)
|
||||
@adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: [:bio, :posts])
|
||||
end
|
||||
@serializer = AuthorSerializer.new(@author)
|
||||
@adapter = ActiveModelSerializers::Adapter::JsonApi.new(@serializer, include: [:bio, :posts])
|
||||
end
|
||||
|
||||
def test_includes_bio_id
|
||||
expected = { data: { type: 'bios', id: '43' } }
|
||||
def test_includes_bio_id
|
||||
expected = { data: { type: 'bios', id: '43' } }
|
||||
|
||||
assert_equal(expected, @adapter.serializable_hash[:data][:relationships][:bio])
|
||||
end
|
||||
assert_equal(expected, @adapter.serializable_hash[:data][:relationships][:bio])
|
||||
end
|
||||
|
||||
def test_includes_linked_bio
|
||||
@adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: [:bio])
|
||||
def test_includes_linked_bio
|
||||
@adapter = ActiveModelSerializers::Adapter::JsonApi.new(@serializer, include: [:bio])
|
||||
|
||||
expected = [
|
||||
{
|
||||
id: '43',
|
||||
type: 'bios',
|
||||
attributes: {
|
||||
content: 'AMS Contributor',
|
||||
rating: nil
|
||||
},
|
||||
relationships: {
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
assert_equal(expected, @adapter.serializable_hash[:included])
|
||||
end
|
||||
|
||||
def test_has_one_with_virtual_value
|
||||
serializer = VirtualValueSerializer.new(@virtual_value)
|
||||
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer)
|
||||
|
||||
expected = {
|
||||
data: {
|
||||
id: '1',
|
||||
type: 'virtual_values',
|
||||
relationships: {
|
||||
maker: { data: { id: 1 } },
|
||||
reviews: { data: [{ id: 1 }, { id: 2 }] }
|
||||
}
|
||||
expected = [
|
||||
{
|
||||
id: '43',
|
||||
type: 'bios',
|
||||
attributes: {
|
||||
content: 'AMS Contributor',
|
||||
rating: nil
|
||||
},
|
||||
relationships: {
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
assert_equal(expected, adapter.serializable_hash)
|
||||
end
|
||||
assert_equal(expected, @adapter.serializable_hash[:included])
|
||||
end
|
||||
|
||||
def test_has_one_with_virtual_value
|
||||
serializer = VirtualValueSerializer.new(@virtual_value)
|
||||
adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
|
||||
|
||||
expected = {
|
||||
data: {
|
||||
id: '1',
|
||||
type: 'virtual_values',
|
||||
relationships: {
|
||||
maker: { data: { id: 1 } },
|
||||
reviews: { data: [{ id: 1 }, { id: 2 }] }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert_equal(expected, adapter.serializable_hash)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,36 +1,34 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class JsonApiTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
ActionController::Base.cache_store.clear
|
||||
@author = Author.new(id: 1, name: 'Steve K.')
|
||||
@post = Post.new(id: 1, title: 'New Post', body: 'Body')
|
||||
@first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
|
||||
@post.comments = [@first_comment, @second_comment]
|
||||
@first_comment.post = @post
|
||||
@second_comment.post = @post
|
||||
@post.author = @author
|
||||
@blog = Blog.new(id: 1, name: 'My Blog!!')
|
||||
@post.blog = @blog
|
||||
end
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApiTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
ActionController::Base.cache_store.clear
|
||||
@author = Author.new(id: 1, name: 'Steve K.')
|
||||
@post = Post.new(id: 1, title: 'New Post', body: 'Body')
|
||||
@first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
|
||||
@post.comments = [@first_comment, @second_comment]
|
||||
@first_comment.post = @post
|
||||
@second_comment.post = @post
|
||||
@post.author = @author
|
||||
@blog = Blog.new(id: 1, name: 'My Blog!!')
|
||||
@post.blog = @blog
|
||||
end
|
||||
|
||||
def test_custom_keys
|
||||
serializer = PostWithCustomKeysSerializer.new(@post)
|
||||
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer)
|
||||
def test_custom_keys
|
||||
serializer = PostWithCustomKeysSerializer.new(@post)
|
||||
adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
|
||||
|
||||
assert_equal({
|
||||
reviews: { data: [
|
||||
{ type: 'comments', id: '1' },
|
||||
{ type: 'comments', id: '2' }
|
||||
] },
|
||||
writer: { data: { type: 'authors', id: '1' } },
|
||||
site: { data: { type: 'blogs', id: '1' } }
|
||||
}, adapter.serializable_hash[:data][:relationships])
|
||||
end
|
||||
assert_equal({
|
||||
reviews: { data: [
|
||||
{ type: 'comments', id: '1' },
|
||||
{ type: 'comments', id: '2' }
|
||||
] },
|
||||
writer: { data: { type: 'authors', id: '1' } },
|
||||
site: { data: { type: 'blogs', id: '1' } }
|
||||
}, adapter.serializable_hash[:data][:relationships])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -5,168 +5,106 @@ class NestedPostSerializer < ActiveModel::Serializer
|
||||
has_many :nested_posts
|
||||
end
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class LinkedTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
@author1 = Author.new(id: 1, name: 'Steve K.')
|
||||
@author2 = Author.new(id: 2, name: 'Tenderlove')
|
||||
@bio1 = Bio.new(id: 1, content: 'AMS Contributor')
|
||||
@bio2 = Bio.new(id: 2, content: 'Rails Contributor')
|
||||
@first_post = Post.new(id: 10, title: 'Hello!!', body: 'Hello, world!!')
|
||||
@second_post = Post.new(id: 20, title: 'New Post', body: 'Body')
|
||||
@third_post = Post.new(id: 30, title: 'Yet Another Post', body: 'Body')
|
||||
@blog = Blog.new({ name: 'AMS Blog' })
|
||||
@first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
|
||||
@first_post.blog = @blog
|
||||
@second_post.blog = @blog
|
||||
@third_post.blog = nil
|
||||
@first_post.comments = [@first_comment, @second_comment]
|
||||
@second_post.comments = []
|
||||
@third_post.comments = []
|
||||
@first_post.author = @author1
|
||||
@second_post.author = @author2
|
||||
@third_post.author = @author1
|
||||
@first_comment.post = @first_post
|
||||
@first_comment.author = nil
|
||||
@second_comment.post = @first_post
|
||||
@second_comment.author = nil
|
||||
@author1.posts = [@first_post, @third_post]
|
||||
@author1.bio = @bio1
|
||||
@author1.roles = []
|
||||
@author2.posts = [@second_post]
|
||||
@author2.bio = @bio2
|
||||
@author2.roles = []
|
||||
@bio1.author = @author1
|
||||
@bio2.author = @author2
|
||||
end
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class LinkedTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
@author1 = Author.new(id: 1, name: 'Steve K.')
|
||||
@author2 = Author.new(id: 2, name: 'Tenderlove')
|
||||
@bio1 = Bio.new(id: 1, content: 'AMS Contributor')
|
||||
@bio2 = Bio.new(id: 2, content: 'Rails Contributor')
|
||||
@first_post = Post.new(id: 10, title: 'Hello!!', body: 'Hello, world!!')
|
||||
@second_post = Post.new(id: 20, title: 'New Post', body: 'Body')
|
||||
@third_post = Post.new(id: 30, title: 'Yet Another Post', body: 'Body')
|
||||
@blog = Blog.new({ name: 'AMS Blog' })
|
||||
@first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
|
||||
@first_post.blog = @blog
|
||||
@second_post.blog = @blog
|
||||
@third_post.blog = nil
|
||||
@first_post.comments = [@first_comment, @second_comment]
|
||||
@second_post.comments = []
|
||||
@third_post.comments = []
|
||||
@first_post.author = @author1
|
||||
@second_post.author = @author2
|
||||
@third_post.author = @author1
|
||||
@first_comment.post = @first_post
|
||||
@first_comment.author = nil
|
||||
@second_comment.post = @first_post
|
||||
@second_comment.author = nil
|
||||
@author1.posts = [@first_post, @third_post]
|
||||
@author1.bio = @bio1
|
||||
@author1.roles = []
|
||||
@author2.posts = [@second_post]
|
||||
@author2.bio = @bio2
|
||||
@author2.roles = []
|
||||
@bio1.author = @author1
|
||||
@bio2.author = @author2
|
||||
end
|
||||
|
||||
def test_include_multiple_posts_and_linked_array
|
||||
serializer = CollectionSerializer.new([@first_post, @second_post])
|
||||
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(
|
||||
serializer,
|
||||
include: [:comments, author: [:bio]]
|
||||
)
|
||||
alt_adapter = ActiveModel::Serializer::Adapter::JsonApi.new(
|
||||
serializer,
|
||||
include: [:comments, author: [:bio]]
|
||||
)
|
||||
def test_include_multiple_posts_and_linked_array
|
||||
serializer = ActiveModel::Serializer::CollectionSerializer.new([@first_post, @second_post])
|
||||
adapter = ActiveModelSerializers::Adapter::JsonApi.new(
|
||||
serializer,
|
||||
include: [:comments, author: [:bio]]
|
||||
)
|
||||
alt_adapter = ActiveModelSerializers::Adapter::JsonApi.new(
|
||||
serializer,
|
||||
include: [:comments, author: [:bio]]
|
||||
)
|
||||
|
||||
expected = {
|
||||
data: [
|
||||
{
|
||||
id: '10',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'Hello!!',
|
||||
body: 'Hello, world!!'
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [{ type: 'comments', id: '1' }, { type: 'comments', id: '2' }] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '20',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'New Post',
|
||||
body: 'Body'
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '2' } }
|
||||
}
|
||||
}
|
||||
],
|
||||
included: [
|
||||
{
|
||||
id: '1',
|
||||
type: 'comments',
|
||||
attributes: {
|
||||
body: 'ZOMG A COMMENT'
|
||||
},
|
||||
relationships: {
|
||||
post: { data: { type: 'posts', id: '10' } },
|
||||
author: { data: nil }
|
||||
}
|
||||
}, {
|
||||
id: '2',
|
||||
type: 'comments',
|
||||
attributes: {
|
||||
body: 'ZOMG ANOTHER COMMENT',
|
||||
},
|
||||
relationships: {
|
||||
post: { data: { type: 'posts', id: '10' } },
|
||||
author: { data: nil }
|
||||
}
|
||||
}, {
|
||||
id: '1',
|
||||
type: 'authors',
|
||||
attributes: {
|
||||
name: 'Steve K.'
|
||||
},
|
||||
relationships: {
|
||||
posts: { data: [{ type: 'posts', id: '10' }, { type: 'posts', id: '30' }] },
|
||||
roles: { data: [] },
|
||||
bio: { data: { type: 'bios', id: '1' } }
|
||||
}
|
||||
}, {
|
||||
id: '1',
|
||||
type: 'bios',
|
||||
attributes: {
|
||||
content: 'AMS Contributor',
|
||||
rating: nil
|
||||
},
|
||||
relationships: {
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
}, {
|
||||
id: '2',
|
||||
type: 'authors',
|
||||
attributes: {
|
||||
name: 'Tenderlove'
|
||||
},
|
||||
relationships: {
|
||||
posts: { data: [{ type: 'posts', id: '20' }] },
|
||||
roles: { data: [] },
|
||||
bio: { data: { type: 'bios', id: '2' } }
|
||||
}
|
||||
}, {
|
||||
id: '2',
|
||||
type: 'bios',
|
||||
attributes: {
|
||||
rating: nil,
|
||||
content: 'Rails Contributor',
|
||||
},
|
||||
relationships: {
|
||||
author: { data: { type: 'authors', id: '2' } }
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
assert_equal expected, adapter.serializable_hash
|
||||
assert_equal expected, alt_adapter.serializable_hash
|
||||
end
|
||||
|
||||
def test_include_multiple_posts_and_linked
|
||||
serializer = BioSerializer.new @bio1
|
||||
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(
|
||||
serializer,
|
||||
include: [author: [:posts]]
|
||||
)
|
||||
alt_adapter = ActiveModel::Serializer::Adapter::JsonApi.new(
|
||||
serializer,
|
||||
include: [author: [:posts]]
|
||||
)
|
||||
|
||||
expected = [
|
||||
expected = {
|
||||
data: [
|
||||
{
|
||||
id: '10',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'Hello!!',
|
||||
body: 'Hello, world!!'
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [{ type: 'comments', id: '1' }, { type: 'comments', id: '2' }] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '20',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'New Post',
|
||||
body: 'Body'
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '2' } }
|
||||
}
|
||||
}
|
||||
],
|
||||
included: [
|
||||
{
|
||||
id: '1',
|
||||
type: 'comments',
|
||||
attributes: {
|
||||
body: 'ZOMG A COMMENT'
|
||||
},
|
||||
relationships: {
|
||||
post: { data: { type: 'posts', id: '10' } },
|
||||
author: { data: nil }
|
||||
}
|
||||
}, {
|
||||
id: '2',
|
||||
type: 'comments',
|
||||
attributes: {
|
||||
body: 'ZOMG ANOTHER COMMENT',
|
||||
},
|
||||
relationships: {
|
||||
post: { data: { type: 'posts', id: '10' } },
|
||||
author: { data: nil }
|
||||
}
|
||||
}, {
|
||||
id: '1',
|
||||
type: 'authors',
|
||||
attributes: {
|
||||
@ -178,215 +116,275 @@ module ActiveModel
|
||||
bio: { data: { type: 'bios', id: '1' } }
|
||||
}
|
||||
}, {
|
||||
id: '10',
|
||||
type: 'posts',
|
||||
id: '1',
|
||||
type: 'bios',
|
||||
attributes: {
|
||||
title: 'Hello!!',
|
||||
body: 'Hello, world!!'
|
||||
content: 'AMS Contributor',
|
||||
rating: nil
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [{ type: 'comments', id: '1' }, { type: 'comments', id: '2' }] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
}, {
|
||||
id: '30',
|
||||
type: 'posts',
|
||||
id: '2',
|
||||
type: 'authors',
|
||||
attributes: {
|
||||
title: 'Yet Another Post',
|
||||
body: 'Body'
|
||||
name: 'Tenderlove'
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
posts: { data: [{ type: 'posts', id: '20' }] },
|
||||
roles: { data: [] },
|
||||
bio: { data: { type: 'bios', id: '2' } }
|
||||
}
|
||||
}, {
|
||||
id: '2',
|
||||
type: 'bios',
|
||||
attributes: {
|
||||
rating: nil,
|
||||
content: 'Rails Contributor',
|
||||
},
|
||||
relationships: {
|
||||
author: { data: { type: 'authors', id: '2' } }
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
assert_equal expected, adapter.serializable_hash[:included]
|
||||
assert_equal expected, alt_adapter.serializable_hash[:included]
|
||||
end
|
||||
|
||||
def test_underscore_model_namespace_for_linked_resource_type
|
||||
spammy_post = Post.new(id: 123)
|
||||
spammy_post.related = [Spam::UnrelatedLink.new(id: 456)]
|
||||
serializer = SpammyPostSerializer.new(spammy_post)
|
||||
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer)
|
||||
relationships = adapter.serializable_hash[:data][:relationships]
|
||||
expected = {
|
||||
related: {
|
||||
data: [{
|
||||
type: 'spam_unrelated_links',
|
||||
id: '456'
|
||||
}]
|
||||
}
|
||||
}
|
||||
assert_equal expected, relationships
|
||||
end
|
||||
|
||||
def test_multiple_references_to_same_resource
|
||||
serializer = CollectionSerializer.new([@first_comment, @second_comment])
|
||||
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(
|
||||
serializer,
|
||||
include: [:post]
|
||||
)
|
||||
|
||||
expected = [
|
||||
{
|
||||
id: '10',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'Hello!!',
|
||||
body: 'Hello, world!!'
|
||||
},
|
||||
relationships: {
|
||||
comments: {
|
||||
data: [{ type: 'comments', id: '1' }, { type: 'comments', id: '2' }]
|
||||
},
|
||||
blog: {
|
||||
data: { type: 'blogs', id: '999' }
|
||||
},
|
||||
author: {
|
||||
data: { type: 'authors', id: '1' }
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
assert_equal expected, adapter.serializable_hash[:included]
|
||||
end
|
||||
|
||||
def test_nil_link_with_specified_serializer
|
||||
@first_post.author = nil
|
||||
serializer = PostPreviewSerializer.new(@first_post)
|
||||
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(
|
||||
serializer,
|
||||
include: [:author]
|
||||
)
|
||||
|
||||
expected = {
|
||||
data: {
|
||||
id: '10',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'Hello!!',
|
||||
body: 'Hello, world!!'
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [{ type: 'comments', id: '1' }, { type: 'comments', id: '2' }] },
|
||||
author: { data: nil }
|
||||
}
|
||||
}
|
||||
}
|
||||
assert_equal expected, adapter.serializable_hash
|
||||
end
|
||||
}
|
||||
assert_equal expected, adapter.serializable_hash
|
||||
assert_equal expected, alt_adapter.serializable_hash
|
||||
end
|
||||
|
||||
class NoDuplicatesTest < ActiveSupport::TestCase
|
||||
Post = Class.new(::Model)
|
||||
Author = Class.new(::Model)
|
||||
def test_include_multiple_posts_and_linked
|
||||
serializer = BioSerializer.new @bio1
|
||||
adapter = ActiveModelSerializers::Adapter::JsonApi.new(
|
||||
serializer,
|
||||
include: [author: [:posts]]
|
||||
)
|
||||
alt_adapter = ActiveModelSerializers::Adapter::JsonApi.new(
|
||||
serializer,
|
||||
include: [author: [:posts]]
|
||||
)
|
||||
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
type 'posts'
|
||||
belongs_to :author
|
||||
end
|
||||
|
||||
class AuthorSerializer < ActiveModel::Serializer
|
||||
type 'authors'
|
||||
has_many :posts
|
||||
end
|
||||
|
||||
def setup
|
||||
@author = Author.new(id: 1, posts: [], roles: [], bio: nil)
|
||||
@post1 = Post.new(id: 1, author: @author)
|
||||
@post2 = Post.new(id: 2, author: @author)
|
||||
@author.posts << @post1
|
||||
@author.posts << @post2
|
||||
|
||||
@nestedpost1 = ::NestedPost.new(id: 1, nested_posts: [])
|
||||
@nestedpost2 = ::NestedPost.new(id: 2, nested_posts: [])
|
||||
@nestedpost1.nested_posts << @nestedpost1
|
||||
@nestedpost1.nested_posts << @nestedpost2
|
||||
@nestedpost2.nested_posts << @nestedpost1
|
||||
@nestedpost2.nested_posts << @nestedpost2
|
||||
end
|
||||
|
||||
def test_no_duplicates
|
||||
hash = ActiveModel::SerializableResource.new(@post1, adapter: :json_api,
|
||||
include: '*.*')
|
||||
.serializable_hash
|
||||
expected = [
|
||||
{
|
||||
type: 'authors', id: '1',
|
||||
relationships: {
|
||||
posts: {
|
||||
data: [
|
||||
{ type: 'posts', id: '1' },
|
||||
{ type: 'posts', id: '2' }
|
||||
]
|
||||
}
|
||||
}
|
||||
expected = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'authors',
|
||||
attributes: {
|
||||
name: 'Steve K.'
|
||||
},
|
||||
{
|
||||
type: 'posts', id: '2',
|
||||
relationships: {
|
||||
author: {
|
||||
data: { type: 'authors', id: '1' }
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
assert_equal(expected, hash[:included])
|
||||
end
|
||||
|
||||
def test_no_duplicates_collection
|
||||
hash = ActiveModel::SerializableResource.new(
|
||||
[@post1, @post2], adapter: :json_api,
|
||||
include: '*.*')
|
||||
.serializable_hash
|
||||
expected = [
|
||||
{
|
||||
type: 'authors', id: '1',
|
||||
relationships: {
|
||||
posts: {
|
||||
data: [
|
||||
{ type: 'posts', id: '1' },
|
||||
{ type: 'posts', id: '2' }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
assert_equal(expected, hash[:included])
|
||||
end
|
||||
|
||||
def test_no_duplicates_global
|
||||
hash = ActiveModel::SerializableResource.new(
|
||||
@nestedpost1,
|
||||
adapter: :json_api,
|
||||
include: '*').serializable_hash
|
||||
expected = [
|
||||
type: 'nested_posts', id: '2',
|
||||
relationships: {
|
||||
nested_posts: {
|
||||
posts: { data: [{ type: 'posts', id: '10' }, { type: 'posts', id: '30' }] },
|
||||
roles: { data: [] },
|
||||
bio: { data: { type: 'bios', id: '1' } }
|
||||
}
|
||||
}, {
|
||||
id: '10',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'Hello!!',
|
||||
body: 'Hello, world!!'
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [{ type: 'comments', id: '1' }, { type: 'comments', id: '2' }] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
}, {
|
||||
id: '30',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'Yet Another Post',
|
||||
body: 'Body'
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [] },
|
||||
blog: { data: { type: 'blogs', id: '999' } },
|
||||
author: { data: { type: 'authors', id: '1' } }
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
assert_equal expected, adapter.serializable_hash[:included]
|
||||
assert_equal expected, alt_adapter.serializable_hash[:included]
|
||||
end
|
||||
|
||||
def test_underscore_model_namespace_for_linked_resource_type
|
||||
spammy_post = Post.new(id: 123)
|
||||
spammy_post.related = [Spam::UnrelatedLink.new(id: 456)]
|
||||
serializer = SpammyPostSerializer.new(spammy_post)
|
||||
adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
|
||||
relationships = adapter.serializable_hash[:data][:relationships]
|
||||
expected = {
|
||||
related: {
|
||||
data: [{
|
||||
type: 'spam_unrelated_links',
|
||||
id: '456'
|
||||
}]
|
||||
}
|
||||
}
|
||||
assert_equal expected, relationships
|
||||
end
|
||||
|
||||
def test_multiple_references_to_same_resource
|
||||
serializer = ActiveModel::Serializer::CollectionSerializer.new([@first_comment, @second_comment])
|
||||
adapter = ActiveModelSerializers::Adapter::JsonApi.new(
|
||||
serializer,
|
||||
include: [:post]
|
||||
)
|
||||
|
||||
expected = [
|
||||
{
|
||||
id: '10',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'Hello!!',
|
||||
body: 'Hello, world!!'
|
||||
},
|
||||
relationships: {
|
||||
comments: {
|
||||
data: [{ type: 'comments', id: '1' }, { type: 'comments', id: '2' }]
|
||||
},
|
||||
blog: {
|
||||
data: { type: 'blogs', id: '999' }
|
||||
},
|
||||
author: {
|
||||
data: { type: 'authors', id: '1' }
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
assert_equal expected, adapter.serializable_hash[:included]
|
||||
end
|
||||
|
||||
def test_nil_link_with_specified_serializer
|
||||
@first_post.author = nil
|
||||
serializer = PostPreviewSerializer.new(@first_post)
|
||||
adapter = ActiveModelSerializers::Adapter::JsonApi.new(
|
||||
serializer,
|
||||
include: [:author]
|
||||
)
|
||||
|
||||
expected = {
|
||||
data: {
|
||||
id: '10',
|
||||
type: 'posts',
|
||||
attributes: {
|
||||
title: 'Hello!!',
|
||||
body: 'Hello, world!!'
|
||||
},
|
||||
relationships: {
|
||||
comments: { data: [{ type: 'comments', id: '1' }, { type: 'comments', id: '2' }] },
|
||||
author: { data: nil }
|
||||
}
|
||||
}
|
||||
}
|
||||
assert_equal expected, adapter.serializable_hash
|
||||
end
|
||||
end
|
||||
|
||||
class NoDuplicatesTest < ActiveSupport::TestCase
|
||||
Post = Class.new(::Model)
|
||||
Author = Class.new(::Model)
|
||||
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
type 'posts'
|
||||
belongs_to :author
|
||||
end
|
||||
|
||||
class AuthorSerializer < ActiveModel::Serializer
|
||||
type 'authors'
|
||||
has_many :posts
|
||||
end
|
||||
|
||||
def setup
|
||||
@author = Author.new(id: 1, posts: [], roles: [], bio: nil)
|
||||
@post1 = Post.new(id: 1, author: @author)
|
||||
@post2 = Post.new(id: 2, author: @author)
|
||||
@author.posts << @post1
|
||||
@author.posts << @post2
|
||||
|
||||
@nestedpost1 = ::NestedPost.new(id: 1, nested_posts: [])
|
||||
@nestedpost2 = ::NestedPost.new(id: 2, nested_posts: [])
|
||||
@nestedpost1.nested_posts << @nestedpost1
|
||||
@nestedpost1.nested_posts << @nestedpost2
|
||||
@nestedpost2.nested_posts << @nestedpost1
|
||||
@nestedpost2.nested_posts << @nestedpost2
|
||||
end
|
||||
|
||||
def test_no_duplicates
|
||||
hash = ActiveModel::SerializableResource.new(@post1, adapter: :json_api,
|
||||
include: '*.*')
|
||||
.serializable_hash
|
||||
expected = [
|
||||
{
|
||||
type: 'authors', id: '1',
|
||||
relationships: {
|
||||
posts: {
|
||||
data: [
|
||||
{ type: 'nested_posts', id: '1' },
|
||||
{ type: 'nested_posts', id: '2' }
|
||||
{ type: 'posts', id: '1' },
|
||||
{ type: 'posts', id: '2' }
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
assert_equal(expected, hash[:included])
|
||||
end
|
||||
},
|
||||
{
|
||||
type: 'posts', id: '2',
|
||||
relationships: {
|
||||
author: {
|
||||
data: { type: 'authors', id: '1' }
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
assert_equal(expected, hash[:included])
|
||||
end
|
||||
|
||||
def test_no_duplicates_collection_global
|
||||
hash = ActiveModel::SerializableResource.new(
|
||||
[@nestedpost1, @nestedpost2],
|
||||
adapter: :json_api,
|
||||
include: '*').serializable_hash
|
||||
assert_nil(hash[:included])
|
||||
end
|
||||
def test_no_duplicates_collection
|
||||
hash = ActiveModel::SerializableResource.new(
|
||||
[@post1, @post2], adapter: :json_api,
|
||||
include: '*.*')
|
||||
.serializable_hash
|
||||
expected = [
|
||||
{
|
||||
type: 'authors', id: '1',
|
||||
relationships: {
|
||||
posts: {
|
||||
data: [
|
||||
{ type: 'posts', id: '1' },
|
||||
{ type: 'posts', id: '2' }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
assert_equal(expected, hash[:included])
|
||||
end
|
||||
|
||||
def test_no_duplicates_global
|
||||
hash = ActiveModel::SerializableResource.new(
|
||||
@nestedpost1,
|
||||
adapter: :json_api,
|
||||
include: '*').serializable_hash
|
||||
expected = [
|
||||
type: 'nested_posts', id: '2',
|
||||
relationships: {
|
||||
nested_posts: {
|
||||
data: [
|
||||
{ type: 'nested_posts', id: '1' },
|
||||
{ type: 'nested_posts', id: '2' }
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
assert_equal(expected, hash[:included])
|
||||
end
|
||||
|
||||
def test_no_duplicates_collection_global
|
||||
hash = ActiveModel::SerializableResource.new(
|
||||
[@nestedpost1, @nestedpost2],
|
||||
adapter: :json_api,
|
||||
include: '*').serializable_hash
|
||||
assert_nil(hash[:included])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,84 +1,82 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class LinksTest < ActiveSupport::TestCase
|
||||
LinkAuthor = Class.new(::Model)
|
||||
class LinkAuthorSerializer < ActiveModel::Serializer
|
||||
link :self do
|
||||
href "//example.com/link_author/#{object.id}"
|
||||
meta stuff: 'value'
|
||||
end
|
||||
|
||||
link :other, '//example.com/resource'
|
||||
|
||||
link :yet_another do
|
||||
"//example.com/resource/#{object.id}"
|
||||
end
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class LinksTest < ActiveSupport::TestCase
|
||||
LinkAuthor = Class.new(::Model)
|
||||
class LinkAuthorSerializer < ActiveModel::Serializer
|
||||
link :self do
|
||||
href "//example.com/link_author/#{object.id}"
|
||||
meta stuff: 'value'
|
||||
end
|
||||
|
||||
def setup
|
||||
@post = Post.new(id: 1337, comments: [], author: nil)
|
||||
@author = LinkAuthor.new(id: 1337, posts: [@post])
|
||||
end
|
||||
link :other, '//example.com/resource'
|
||||
|
||||
def test_toplevel_links
|
||||
hash = ActiveModel::SerializableResource.new(
|
||||
@post,
|
||||
adapter: :json_api,
|
||||
links: {
|
||||
self: {
|
||||
href: '//example.com/posts',
|
||||
meta: {
|
||||
stuff: 'value'
|
||||
}
|
||||
}
|
||||
}).serializable_hash
|
||||
expected = {
|
||||
link :yet_another do
|
||||
"//example.com/resource/#{object.id}"
|
||||
end
|
||||
end
|
||||
|
||||
def setup
|
||||
@post = Post.new(id: 1337, comments: [], author: nil)
|
||||
@author = LinkAuthor.new(id: 1337, posts: [@post])
|
||||
end
|
||||
|
||||
def test_toplevel_links
|
||||
hash = ActiveModel::SerializableResource.new(
|
||||
@post,
|
||||
adapter: :json_api,
|
||||
links: {
|
||||
self: {
|
||||
href: '//example.com/posts',
|
||||
meta: {
|
||||
stuff: 'value'
|
||||
}
|
||||
}
|
||||
}).serializable_hash
|
||||
expected = {
|
||||
self: {
|
||||
href: '//example.com/posts',
|
||||
meta: {
|
||||
stuff: 'value'
|
||||
}
|
||||
}
|
||||
assert_equal(expected, hash[:links])
|
||||
end
|
||||
}
|
||||
assert_equal(expected, hash[:links])
|
||||
end
|
||||
|
||||
def test_nil_toplevel_links
|
||||
hash = ActiveModel::SerializableResource.new(
|
||||
@post,
|
||||
adapter: :json_api,
|
||||
links: nil
|
||||
).serializable_hash
|
||||
refute hash.key?(:links), 'No links key to be output'
|
||||
end
|
||||
def test_nil_toplevel_links
|
||||
hash = ActiveModel::SerializableResource.new(
|
||||
@post,
|
||||
adapter: :json_api,
|
||||
links: nil
|
||||
).serializable_hash
|
||||
refute hash.key?(:links), 'No links key to be output'
|
||||
end
|
||||
|
||||
def test_nil_toplevel_links_json_adapter
|
||||
hash = ActiveModel::SerializableResource.new(
|
||||
@post,
|
||||
adapter: :json,
|
||||
links: nil
|
||||
).serializable_hash
|
||||
refute hash.key?(:links), 'No links key to be output'
|
||||
end
|
||||
def test_nil_toplevel_links_json_adapter
|
||||
hash = ActiveModel::SerializableResource.new(
|
||||
@post,
|
||||
adapter: :json,
|
||||
links: nil
|
||||
).serializable_hash
|
||||
refute hash.key?(:links), 'No links key to be output'
|
||||
end
|
||||
|
||||
def test_resource_links
|
||||
hash = serializable(@author, adapter: :json_api).serializable_hash
|
||||
expected = {
|
||||
self: {
|
||||
href: '//example.com/link_author/1337',
|
||||
meta: {
|
||||
stuff: 'value'
|
||||
}
|
||||
},
|
||||
other: '//example.com/resource',
|
||||
yet_another: '//example.com/resource/1337'
|
||||
}
|
||||
assert_equal(expected, hash[:data][:links])
|
||||
end
|
||||
def test_resource_links
|
||||
hash = serializable(@author, adapter: :json_api).serializable_hash
|
||||
expected = {
|
||||
self: {
|
||||
href: '//example.com/link_author/1337',
|
||||
meta: {
|
||||
stuff: 'value'
|
||||
}
|
||||
},
|
||||
other: '//example.com/resource',
|
||||
yet_another: '//example.com/resource/1337'
|
||||
}
|
||||
assert_equal(expected, hash[:data][:links])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -4,110 +4,108 @@ require 'kaminari'
|
||||
require 'kaminari/hooks'
|
||||
::Kaminari::Hooks.init
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class PaginationLinksTest < ActiveSupport::TestCase
|
||||
URI = 'http://example.com'
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class PaginationLinksTest < ActiveSupport::TestCase
|
||||
URI = 'http://example.com'
|
||||
|
||||
def setup
|
||||
ActionController::Base.cache_store.clear
|
||||
@array = [
|
||||
Profile.new({ id: 1, name: 'Name 1', description: 'Description 1', comments: 'Comments 1' }),
|
||||
Profile.new({ id: 2, name: 'Name 2', description: 'Description 2', comments: 'Comments 2' }),
|
||||
Profile.new({ id: 3, name: 'Name 3', description: 'Description 3', comments: 'Comments 3' })
|
||||
def setup
|
||||
ActionController::Base.cache_store.clear
|
||||
@array = [
|
||||
Profile.new({ id: 1, name: 'Name 1', description: 'Description 1', comments: 'Comments 1' }),
|
||||
Profile.new({ id: 2, name: 'Name 2', description: 'Description 2', comments: 'Comments 2' }),
|
||||
Profile.new({ id: 3, name: 'Name 3', description: 'Description 3', comments: 'Comments 3' })
|
||||
]
|
||||
end
|
||||
|
||||
def mock_request(query_parameters = {}, original_url = URI)
|
||||
context = Minitest::Mock.new
|
||||
context.expect(:request_url, original_url)
|
||||
context.expect(:query_parameters, query_parameters)
|
||||
@options = {}
|
||||
@options[:serialization_context] = context
|
||||
end
|
||||
|
||||
def load_adapter(paginated_collection, options = {})
|
||||
options = options.merge(adapter: :json_api)
|
||||
ActiveModel::SerializableResource.new(paginated_collection, options)
|
||||
end
|
||||
|
||||
def using_kaminari
|
||||
Kaminari.paginate_array(@array).page(2).per(1)
|
||||
end
|
||||
|
||||
def using_will_paginate
|
||||
@array.paginate(page: 2, per_page: 1)
|
||||
end
|
||||
|
||||
def data
|
||||
{ data: [
|
||||
{ id: '1', type: 'profiles', attributes: { name: 'Name 1', description: 'Description 1' } },
|
||||
{ id: '2', type: 'profiles', attributes: { name: 'Name 2', description: 'Description 2' } },
|
||||
{ id: '3', type: 'profiles', attributes: { name: 'Name 3', description: 'Description 3' } }
|
||||
]
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
def mock_request(query_parameters = {}, original_url = URI)
|
||||
context = Minitest::Mock.new
|
||||
context.expect(:request_url, original_url)
|
||||
context.expect(:query_parameters, query_parameters)
|
||||
@options = {}
|
||||
@options[:serialization_context] = context
|
||||
end
|
||||
|
||||
def load_adapter(paginated_collection, options = {})
|
||||
options = options.merge(adapter: :json_api)
|
||||
ActiveModel::SerializableResource.new(paginated_collection, options)
|
||||
end
|
||||
|
||||
def using_kaminari
|
||||
Kaminari.paginate_array(@array).page(2).per(1)
|
||||
end
|
||||
|
||||
def using_will_paginate
|
||||
@array.paginate(page: 2, per_page: 1)
|
||||
end
|
||||
|
||||
def data
|
||||
{ data: [
|
||||
{ id: '1', type: 'profiles', attributes: { name: 'Name 1', description: 'Description 1' } },
|
||||
{ id: '2', type: 'profiles', attributes: { name: 'Name 2', description: 'Description 2' } },
|
||||
{ id: '3', type: 'profiles', attributes: { name: 'Name 3', description: 'Description 3' } }
|
||||
]
|
||||
def links
|
||||
{
|
||||
links: {
|
||||
self: "#{URI}?page%5Bnumber%5D=2&page%5Bsize%5D=1",
|
||||
first: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=1",
|
||||
prev: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=1",
|
||||
next: "#{URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1",
|
||||
last: "#{URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1"
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def expected_response_without_pagination_links
|
||||
data
|
||||
end
|
||||
|
||||
def expected_response_with_pagination_links
|
||||
{}.tap do |hash|
|
||||
hash[:data] = [data.values.flatten.second]
|
||||
hash.merge! links
|
||||
end
|
||||
end
|
||||
|
||||
def links
|
||||
{
|
||||
links: {
|
||||
self: "#{URI}?page%5Bnumber%5D=2&page%5Bsize%5D=1",
|
||||
first: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=1",
|
||||
prev: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=1",
|
||||
next: "#{URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1",
|
||||
last: "#{URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1"
|
||||
}
|
||||
}
|
||||
def expected_response_with_pagination_links_and_additional_params
|
||||
new_links = links[:links].each_with_object({}) { |(key, value), hash| hash[key] = "#{value}&test=test" }
|
||||
{}.tap do |hash|
|
||||
hash[:data] = [data.values.flatten.second]
|
||||
hash.merge! links: new_links
|
||||
end
|
||||
end
|
||||
|
||||
def expected_response_without_pagination_links
|
||||
data
|
||||
end
|
||||
def test_pagination_links_using_kaminari
|
||||
adapter = load_adapter(using_kaminari)
|
||||
|
||||
def expected_response_with_pagination_links
|
||||
{}.tap do |hash|
|
||||
hash[:data] = [data.values.flatten.second]
|
||||
hash.merge! links
|
||||
end
|
||||
end
|
||||
mock_request
|
||||
assert_equal expected_response_with_pagination_links, adapter.serializable_hash(@options)
|
||||
end
|
||||
|
||||
def expected_response_with_pagination_links_and_additional_params
|
||||
new_links = links[:links].each_with_object({}) { |(key, value), hash| hash[key] = "#{value}&test=test" }
|
||||
{}.tap do |hash|
|
||||
hash[:data] = [data.values.flatten.second]
|
||||
hash.merge! links: new_links
|
||||
end
|
||||
end
|
||||
def test_pagination_links_using_will_paginate
|
||||
adapter = load_adapter(using_will_paginate)
|
||||
|
||||
def test_pagination_links_using_kaminari
|
||||
adapter = load_adapter(using_kaminari)
|
||||
mock_request
|
||||
assert_equal expected_response_with_pagination_links, adapter.serializable_hash(@options)
|
||||
end
|
||||
|
||||
mock_request
|
||||
assert_equal expected_response_with_pagination_links, adapter.serializable_hash(@options)
|
||||
end
|
||||
def test_pagination_links_with_additional_params
|
||||
adapter = load_adapter(using_will_paginate)
|
||||
|
||||
def test_pagination_links_using_will_paginate
|
||||
adapter = load_adapter(using_will_paginate)
|
||||
mock_request({ test: 'test' })
|
||||
assert_equal expected_response_with_pagination_links_and_additional_params,
|
||||
adapter.serializable_hash(@options)
|
||||
end
|
||||
|
||||
mock_request
|
||||
assert_equal expected_response_with_pagination_links, adapter.serializable_hash(@options)
|
||||
end
|
||||
def test_not_showing_pagination_links
|
||||
adapter = load_adapter(@array)
|
||||
|
||||
def test_pagination_links_with_additional_params
|
||||
adapter = load_adapter(using_will_paginate)
|
||||
|
||||
mock_request({ test: 'test' })
|
||||
assert_equal expected_response_with_pagination_links_and_additional_params,
|
||||
adapter.serializable_hash(@options)
|
||||
end
|
||||
|
||||
def test_not_showing_pagination_links
|
||||
adapter = load_adapter(@array)
|
||||
|
||||
assert_equal expected_response_without_pagination_links, adapter.serializable_hash
|
||||
end
|
||||
assert_equal expected_response_without_pagination_links, adapter.serializable_hash
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,136 +1,134 @@
|
||||
require 'test_helper'
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class JsonApi
|
||||
module Deserialization
|
||||
class ParseTest < Minitest::Test
|
||||
def setup
|
||||
@hash = {
|
||||
'data' => {
|
||||
'type' => 'photos',
|
||||
'id' => 'zorglub',
|
||||
'attributes' => {
|
||||
'title' => 'Ember Hamster',
|
||||
'src' => 'http://example.com/images/productivity.png'
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi
|
||||
module Deserialization
|
||||
class ParseTest < Minitest::Test
|
||||
def setup
|
||||
@hash = {
|
||||
'data' => {
|
||||
'type' => 'photos',
|
||||
'id' => 'zorglub',
|
||||
'attributes' => {
|
||||
'title' => 'Ember Hamster',
|
||||
'src' => 'http://example.com/images/productivity.png'
|
||||
},
|
||||
'relationships' => {
|
||||
'author' => {
|
||||
'data' => nil
|
||||
},
|
||||
'relationships' => {
|
||||
'author' => {
|
||||
'data' => nil
|
||||
},
|
||||
'photographer' => {
|
||||
'data' => { 'type' => 'people', 'id' => '9' }
|
||||
},
|
||||
'comments' => {
|
||||
'data' => [
|
||||
{ 'type' => 'comments', 'id' => '1' },
|
||||
{ 'type' => 'comments', 'id' => '2' }
|
||||
]
|
||||
}
|
||||
'photographer' => {
|
||||
'data' => { 'type' => 'people', 'id' => '9' }
|
||||
},
|
||||
'comments' => {
|
||||
'data' => [
|
||||
{ 'type' => 'comments', 'id' => '1' },
|
||||
{ 'type' => 'comments', 'id' => '2' }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@params = ActionController::Parameters.new(@hash)
|
||||
@expected = {
|
||||
id: 'zorglub',
|
||||
title: 'Ember Hamster',
|
||||
src: 'http://example.com/images/productivity.png',
|
||||
author_id: nil,
|
||||
photographer_id: '9',
|
||||
comment_ids: %w(1 2)
|
||||
}
|
||||
}
|
||||
@params = ActionController::Parameters.new(@hash)
|
||||
@expected = {
|
||||
id: 'zorglub',
|
||||
title: 'Ember Hamster',
|
||||
src: 'http://example.com/images/productivity.png',
|
||||
author_id: nil,
|
||||
photographer_id: '9',
|
||||
comment_ids: %w(1 2)
|
||||
}
|
||||
|
||||
@illformed_payloads = [nil,
|
||||
{},
|
||||
{
|
||||
'data' => nil
|
||||
}, {
|
||||
'data' => { 'attributes' => [] }
|
||||
}, {
|
||||
'data' => { 'relationships' => [] }
|
||||
}, {
|
||||
'data' => {
|
||||
'relationships' => { 'rel' => nil }
|
||||
}
|
||||
}, {
|
||||
'data' => {
|
||||
'relationships' => { 'rel' => {} }
|
||||
}
|
||||
}]
|
||||
@illformed_payloads = [nil,
|
||||
{},
|
||||
{
|
||||
'data' => nil
|
||||
}, {
|
||||
'data' => { 'attributes' => [] }
|
||||
}, {
|
||||
'data' => { 'relationships' => [] }
|
||||
}, {
|
||||
'data' => {
|
||||
'relationships' => { 'rel' => nil }
|
||||
}
|
||||
}, {
|
||||
'data' => {
|
||||
'relationships' => { 'rel' => {} }
|
||||
}
|
||||
}]
|
||||
end
|
||||
|
||||
def test_hash
|
||||
parsed_hash = ActiveModelSerializers::Adapter::JsonApi::Deserialization.parse!(@hash)
|
||||
assert_equal(@expected, parsed_hash)
|
||||
end
|
||||
|
||||
def test_actioncontroller_parameters
|
||||
assert_equal(false, @params.permitted?)
|
||||
parsed_hash = ActiveModelSerializers::Adapter::JsonApi::Deserialization.parse!(@params)
|
||||
assert_equal(@expected, parsed_hash)
|
||||
end
|
||||
|
||||
def test_illformed_payloads_safe
|
||||
@illformed_payloads.each do |p|
|
||||
parsed_hash = ActiveModelSerializers::Adapter::JsonApi::Deserialization.parse(p)
|
||||
assert_equal({}, parsed_hash)
|
||||
end
|
||||
end
|
||||
|
||||
def test_hash
|
||||
parsed_hash = ActiveModel::Serializer::Adapter::JsonApi::Deserialization.parse!(@hash)
|
||||
assert_equal(@expected, parsed_hash)
|
||||
end
|
||||
|
||||
def test_actioncontroller_parameters
|
||||
assert_equal(false, @params.permitted?)
|
||||
parsed_hash = ActiveModel::Serializer::Adapter::JsonApi::Deserialization.parse!(@params)
|
||||
assert_equal(@expected, parsed_hash)
|
||||
end
|
||||
|
||||
def test_illformed_payloads_safe
|
||||
@illformed_payloads.each do |p|
|
||||
parsed_hash = ActiveModel::Serializer::Adapter::JsonApi::Deserialization.parse(p)
|
||||
assert_equal({}, parsed_hash)
|
||||
def test_illformed_payloads_unsafe
|
||||
@illformed_payloads.each do |p|
|
||||
assert_raises(InvalidDocument) do
|
||||
ActiveModelSerializers::Adapter::JsonApi::Deserialization.parse!(p)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_illformed_payloads_unsafe
|
||||
@illformed_payloads.each do |p|
|
||||
assert_raises(InvalidDocument) do
|
||||
ActiveModel::Serializer::Adapter::JsonApi::Deserialization.parse!(p)
|
||||
end
|
||||
end
|
||||
end
|
||||
def test_filter_fields_only
|
||||
parsed_hash = ActiveModelSerializers::Adapter::JsonApi::Deserialization.parse!(@hash, only: [:id, :title, :author])
|
||||
expected = {
|
||||
id: 'zorglub',
|
||||
title: 'Ember Hamster',
|
||||
author_id: nil
|
||||
}
|
||||
assert_equal(expected, parsed_hash)
|
||||
end
|
||||
|
||||
def test_filter_fields_only
|
||||
parsed_hash = ActiveModel::Serializer::Adapter::JsonApi::Deserialization.parse!(@hash, only: [:id, :title, :author])
|
||||
expected = {
|
||||
id: 'zorglub',
|
||||
title: 'Ember Hamster',
|
||||
author_id: nil
|
||||
}
|
||||
assert_equal(expected, parsed_hash)
|
||||
end
|
||||
def test_filter_fields_except
|
||||
parsed_hash = ActiveModelSerializers::Adapter::JsonApi::Deserialization.parse!(@hash, except: [:id, :title, :author])
|
||||
expected = {
|
||||
src: 'http://example.com/images/productivity.png',
|
||||
photographer_id: '9',
|
||||
comment_ids: %w(1 2)
|
||||
}
|
||||
assert_equal(expected, parsed_hash)
|
||||
end
|
||||
|
||||
def test_filter_fields_except
|
||||
parsed_hash = ActiveModel::Serializer::Adapter::JsonApi::Deserialization.parse!(@hash, except: [:id, :title, :author])
|
||||
expected = {
|
||||
src: 'http://example.com/images/productivity.png',
|
||||
photographer_id: '9',
|
||||
comment_ids: %w(1 2)
|
||||
}
|
||||
assert_equal(expected, parsed_hash)
|
||||
end
|
||||
def test_keys
|
||||
parsed_hash = ActiveModelSerializers::Adapter::JsonApi::Deserialization.parse!(@hash, keys: { author: :user, title: :post_title })
|
||||
expected = {
|
||||
id: 'zorglub',
|
||||
post_title: 'Ember Hamster',
|
||||
src: 'http://example.com/images/productivity.png',
|
||||
user_id: nil,
|
||||
photographer_id: '9',
|
||||
comment_ids: %w(1 2)
|
||||
}
|
||||
assert_equal(expected, parsed_hash)
|
||||
end
|
||||
|
||||
def test_keys
|
||||
parsed_hash = ActiveModel::Serializer::Adapter::JsonApi::Deserialization.parse!(@hash, keys: { author: :user, title: :post_title })
|
||||
expected = {
|
||||
id: 'zorglub',
|
||||
post_title: 'Ember Hamster',
|
||||
src: 'http://example.com/images/productivity.png',
|
||||
user_id: nil,
|
||||
photographer_id: '9',
|
||||
comment_ids: %w(1 2)
|
||||
}
|
||||
assert_equal(expected, parsed_hash)
|
||||
end
|
||||
|
||||
def test_polymorphic
|
||||
parsed_hash = ActiveModel::Serializer::Adapter::JsonApi::Deserialization.parse!(@hash, polymorphic: [:photographer])
|
||||
expected = {
|
||||
id: 'zorglub',
|
||||
title: 'Ember Hamster',
|
||||
src: 'http://example.com/images/productivity.png',
|
||||
author_id: nil,
|
||||
photographer_id: '9',
|
||||
photographer_type: 'people',
|
||||
comment_ids: %w(1 2)
|
||||
}
|
||||
assert_equal(expected, parsed_hash)
|
||||
end
|
||||
def test_polymorphic
|
||||
parsed_hash = ActiveModelSerializers::Adapter::JsonApi::Deserialization.parse!(@hash, polymorphic: [:photographer])
|
||||
expected = {
|
||||
id: 'zorglub',
|
||||
title: 'Ember Hamster',
|
||||
src: 'http://example.com/images/productivity.png',
|
||||
author_id: nil,
|
||||
photographer_id: '9',
|
||||
photographer_type: 'people',
|
||||
comment_ids: %w(1 2)
|
||||
}
|
||||
assert_equal(expected, parsed_hash)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,82 +1,80 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class TopLevelJsonApiTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
@author = Author.new(id: 1, name: 'Steve K.')
|
||||
@author.bio = nil
|
||||
@author.roles = []
|
||||
@blog = Blog.new(id: 23, name: 'AMS Blog')
|
||||
@post = Post.new(id: 42, title: 'New Post', body: 'Body')
|
||||
@anonymous_post = Post.new(id: 43, title: 'Hello!!', body: 'Hello, world!!')
|
||||
@comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@post.comments = [@comment]
|
||||
@post.blog = @blog
|
||||
@anonymous_post.comments = []
|
||||
@anonymous_post.blog = nil
|
||||
@comment.post = @post
|
||||
@comment.author = nil
|
||||
@post.author = @author
|
||||
@anonymous_post.author = nil
|
||||
@blog = Blog.new(id: 1, name: 'My Blog!!')
|
||||
@blog.writer = @author
|
||||
@blog.articles = [@post, @anonymous_post]
|
||||
@author.posts = []
|
||||
end
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class TopLevelJsonApiTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
@author = Author.new(id: 1, name: 'Steve K.')
|
||||
@author.bio = nil
|
||||
@author.roles = []
|
||||
@blog = Blog.new(id: 23, name: 'AMS Blog')
|
||||
@post = Post.new(id: 42, title: 'New Post', body: 'Body')
|
||||
@anonymous_post = Post.new(id: 43, title: 'Hello!!', body: 'Hello, world!!')
|
||||
@comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@post.comments = [@comment]
|
||||
@post.blog = @blog
|
||||
@anonymous_post.comments = []
|
||||
@anonymous_post.blog = nil
|
||||
@comment.post = @post
|
||||
@comment.author = nil
|
||||
@post.author = @author
|
||||
@anonymous_post.author = nil
|
||||
@blog = Blog.new(id: 1, name: 'My Blog!!')
|
||||
@blog.writer = @author
|
||||
@blog.articles = [@post, @anonymous_post]
|
||||
@author.posts = []
|
||||
end
|
||||
|
||||
def test_toplevel_jsonapi_defaults_to_false
|
||||
assert_equal config.fetch(:jsonapi_include_toplevel_object), false
|
||||
end
|
||||
def test_toplevel_jsonapi_defaults_to_false
|
||||
assert_equal config.fetch(:jsonapi_include_toplevel_object), false
|
||||
end
|
||||
|
||||
def test_disable_toplevel_jsonapi
|
||||
with_config(jsonapi_include_toplevel_object: false) do
|
||||
hash = serialize(@post)
|
||||
assert_nil(hash[:jsonapi])
|
||||
end
|
||||
def test_disable_toplevel_jsonapi
|
||||
with_config(jsonapi_include_toplevel_object: false) do
|
||||
hash = serialize(@post)
|
||||
assert_nil(hash[:jsonapi])
|
||||
end
|
||||
end
|
||||
|
||||
def test_enable_toplevel_jsonapi
|
||||
with_config(jsonapi_include_toplevel_object: true) do
|
||||
hash = serialize(@post)
|
||||
refute_nil(hash[:jsonapi])
|
||||
end
|
||||
def test_enable_toplevel_jsonapi
|
||||
with_config(jsonapi_include_toplevel_object: true) do
|
||||
hash = serialize(@post)
|
||||
refute_nil(hash[:jsonapi])
|
||||
end
|
||||
end
|
||||
|
||||
def test_default_toplevel_jsonapi_version
|
||||
with_config(jsonapi_include_toplevel_object: true) do
|
||||
hash = serialize(@post)
|
||||
assert_equal('1.0', hash[:jsonapi][:version])
|
||||
end
|
||||
def test_default_toplevel_jsonapi_version
|
||||
with_config(jsonapi_include_toplevel_object: true) do
|
||||
hash = serialize(@post)
|
||||
assert_equal('1.0', hash[:jsonapi][:version])
|
||||
end
|
||||
end
|
||||
|
||||
def test_toplevel_jsonapi_no_meta
|
||||
with_config(jsonapi_include_toplevel_object: true) do
|
||||
hash = serialize(@post)
|
||||
assert_nil(hash[:jsonapi][:meta])
|
||||
end
|
||||
def test_toplevel_jsonapi_no_meta
|
||||
with_config(jsonapi_include_toplevel_object: true) do
|
||||
hash = serialize(@post)
|
||||
assert_nil(hash[:jsonapi][:meta])
|
||||
end
|
||||
end
|
||||
|
||||
def test_toplevel_jsonapi_meta
|
||||
new_config = {
|
||||
jsonapi_include_toplevel_object: true,
|
||||
jsonapi_toplevel_meta: {
|
||||
'copyright' => 'Copyright 2015 Example Corp.'
|
||||
}
|
||||
def test_toplevel_jsonapi_meta
|
||||
new_config = {
|
||||
jsonapi_include_toplevel_object: true,
|
||||
jsonapi_toplevel_meta: {
|
||||
'copyright' => 'Copyright 2015 Example Corp.'
|
||||
}
|
||||
with_config(new_config) do
|
||||
hash = serialize(@post)
|
||||
assert_equal(new_config[:jsonapi_toplevel_meta], hash.fetch(:jsonapi).fetch(:meta))
|
||||
end
|
||||
}
|
||||
with_config(new_config) do
|
||||
hash = serialize(@post)
|
||||
assert_equal(new_config[:jsonapi_toplevel_meta], hash.fetch(:jsonapi).fetch(:meta))
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
def serialize(resource, options = {})
|
||||
serializable(resource, { adapter: :json_api }.merge!(options)).serializable_hash
|
||||
end
|
||||
def serialize(resource, options = {})
|
||||
serializable(resource, { adapter: :json_api }.merge!(options)).serializable_hash
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,46 +1,44 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class JsonTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
ActionController::Base.cache_store.clear
|
||||
@author = Author.new(id: 1, name: 'Steve K.')
|
||||
@post = Post.new(id: 1, title: 'New Post', body: 'Body')
|
||||
@first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
|
||||
@post.comments = [@first_comment, @second_comment]
|
||||
@first_comment.post = @post
|
||||
@second_comment.post = @post
|
||||
@post.author = @author
|
||||
@blog = Blog.new(id: 1, name: 'My Blog!!')
|
||||
@post.blog = @blog
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
ActionController::Base.cache_store.clear
|
||||
@author = Author.new(id: 1, name: 'Steve K.')
|
||||
@post = Post.new(id: 1, title: 'New Post', body: 'Body')
|
||||
@first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
|
||||
@post.comments = [@first_comment, @second_comment]
|
||||
@first_comment.post = @post
|
||||
@second_comment.post = @post
|
||||
@post.author = @author
|
||||
@blog = Blog.new(id: 1, name: 'My Blog!!')
|
||||
@post.blog = @blog
|
||||
|
||||
@serializer = PostSerializer.new(@post)
|
||||
@adapter = ActiveModel::Serializer::Adapter::Json.new(@serializer)
|
||||
end
|
||||
@serializer = PostSerializer.new(@post)
|
||||
@adapter = ActiveModelSerializers::Adapter::Json.new(@serializer)
|
||||
end
|
||||
|
||||
def test_has_many
|
||||
assert_equal([
|
||||
{ id: 1, body: 'ZOMG A COMMENT' },
|
||||
{ id: 2, body: 'ZOMG ANOTHER COMMENT' }
|
||||
], @adapter.serializable_hash[:post][:comments])
|
||||
end
|
||||
def test_has_many
|
||||
assert_equal([
|
||||
{ id: 1, body: 'ZOMG A COMMENT' },
|
||||
{ id: 2, body: 'ZOMG ANOTHER COMMENT' }
|
||||
], @adapter.serializable_hash[:post][:comments])
|
||||
end
|
||||
|
||||
def test_custom_keys
|
||||
serializer = PostWithCustomKeysSerializer.new(@post)
|
||||
adapter = ActiveModel::Serializer::Adapter::Json.new(serializer)
|
||||
def test_custom_keys
|
||||
serializer = PostWithCustomKeysSerializer.new(@post)
|
||||
adapter = ActiveModelSerializers::Adapter::Json.new(serializer)
|
||||
|
||||
assert_equal({
|
||||
id: 1,
|
||||
reviews: [{ id: 1, body: 'ZOMG A COMMENT' },
|
||||
{ id: 2, body: 'ZOMG ANOTHER COMMENT' }
|
||||
],
|
||||
writer: { id: 1, name: 'Steve K.' },
|
||||
site: { id: 1, name: 'My Blog!!' }
|
||||
}, adapter.serializable_hash[:post])
|
||||
end
|
||||
assert_equal({
|
||||
id: 1,
|
||||
reviews: [{ id: 1, body: 'ZOMG A COMMENT' },
|
||||
{ id: 2, body: 'ZOMG ANOTHER COMMENT' }
|
||||
],
|
||||
writer: { id: 1, name: 'Steve K.' },
|
||||
site: { id: 1, name: 'My Blog!!' }
|
||||
}, adapter.serializable_hash[:post])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,23 +1,21 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class NullTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||
serializer = ProfileSerializer.new(profile)
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class NullTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||
serializer = ProfileSerializer.new(profile)
|
||||
|
||||
@adapter = Null.new(serializer)
|
||||
end
|
||||
@adapter = Null.new(serializer)
|
||||
end
|
||||
|
||||
def test_serializable_hash
|
||||
assert_equal({}, @adapter.serializable_hash)
|
||||
end
|
||||
def test_serializable_hash
|
||||
assert_equal({}, @adapter.serializable_hash)
|
||||
end
|
||||
|
||||
def test_it_returns_empty_json
|
||||
assert_equal('{}', @adapter.to_json)
|
||||
end
|
||||
def test_it_returns_empty_json
|
||||
assert_equal('{}', @adapter.to_json)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,42 +1,40 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class AdapterTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
profile = Profile.new
|
||||
@serializer = ProfileSerializer.new(profile)
|
||||
@adapter = ActiveModel::Serializer::Adapter::Base.new(@serializer)
|
||||
module ActiveModelSerializers
|
||||
class AdapterTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
profile = Profile.new
|
||||
@serializer = ProfileSerializer.new(profile)
|
||||
@adapter = ActiveModelSerializers::Adapter::Base.new(@serializer)
|
||||
end
|
||||
|
||||
def test_serializable_hash_is_abstract_method
|
||||
assert_raises(NotImplementedError) do
|
||||
@adapter.serializable_hash(only: [:name])
|
||||
end
|
||||
end
|
||||
|
||||
def test_serializable_hash_is_abstract_method
|
||||
assert_raises(NotImplementedError) do
|
||||
@adapter.serializable_hash(only: [:name])
|
||||
end
|
||||
end
|
||||
def test_serializer
|
||||
assert_equal @serializer, @adapter.serializer
|
||||
end
|
||||
|
||||
def test_serializer
|
||||
assert_equal @serializer, @adapter.serializer
|
||||
end
|
||||
def test_create_adapter
|
||||
adapter = ActiveModelSerializers::Adapter.create(@serializer)
|
||||
assert_equal ActiveModelSerializers::Adapter::Attributes, adapter.class
|
||||
end
|
||||
|
||||
def test_create_adapter
|
||||
adapter = ActiveModel::Serializer::Adapter.create(@serializer)
|
||||
assert_equal ActiveModel::Serializer::Adapter::Attributes, adapter.class
|
||||
end
|
||||
def test_create_adapter_with_override
|
||||
adapter = ActiveModelSerializers::Adapter.create(@serializer, { adapter: :json_api })
|
||||
assert_equal ActiveModelSerializers::Adapter::JsonApi, adapter.class
|
||||
end
|
||||
|
||||
def test_create_adapter_with_override
|
||||
adapter = ActiveModel::Serializer::Adapter.create(@serializer, { adapter: :json_api })
|
||||
assert_equal ActiveModel::Serializer::Adapter::JsonApi, adapter.class
|
||||
end
|
||||
def test_inflected_adapter_class_for_known_adapter
|
||||
ActiveSupport::Inflector.inflections(:en) { |inflect| inflect.acronym 'API' }
|
||||
klass = ActiveModelSerializers::Adapter.adapter_class(:json_api)
|
||||
|
||||
def test_inflected_adapter_class_for_known_adapter
|
||||
ActiveSupport::Inflector.inflections(:en) { |inflect| inflect.acronym 'API' }
|
||||
klass = ActiveModel::Serializer::Adapter.adapter_class(:json_api)
|
||||
ActiveSupport::Inflector.inflections.acronyms.clear
|
||||
|
||||
ActiveSupport::Inflector.inflections.acronyms.clear
|
||||
|
||||
assert_equal ActiveModel::Serializer::Adapter::JsonApi, klass
|
||||
end
|
||||
assert_equal ActiveModelSerializers::Adapter::JsonApi, klass
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -6,11 +6,11 @@ module ActiveModel
|
||||
# Minitest.run_one_method isn't present in minitest 4
|
||||
if $minitest_version > 4 # rubocop:disable Style/GlobalVars
|
||||
class ArraySerializerTest < CollectionSerializerTest
|
||||
extend ActiveSupport::Testing::Stream
|
||||
extend Minitest::Assertions
|
||||
def self.run_one_method(*)
|
||||
stderr = (capture(:stderr) do
|
||||
_, stderr = capture_io do
|
||||
super
|
||||
end)
|
||||
end
|
||||
if stderr !~ /Calling deprecated ArraySerializer/
|
||||
fail Minitest::Assertion, stderr
|
||||
end
|
||||
@ -22,14 +22,13 @@ module ActiveModel
|
||||
end
|
||||
else
|
||||
class ArraySerializerTest < ActiveSupport::TestCase
|
||||
extend ActiveSupport::Testing::Stream
|
||||
def test_json_key_with_root_warns_when_using_array_serializer
|
||||
stderr = (capture(:stderr) do
|
||||
_, stderr = capture_io do
|
||||
comment = Comment.new
|
||||
post = Post.new
|
||||
serializer = ArraySerializer.new([comment, post])
|
||||
assert_equal 'comments', serializer.json_key
|
||||
end)
|
||||
end
|
||||
assert_match(/Calling deprecated ArraySerializer/, stderr)
|
||||
end
|
||||
end
|
||||
|
||||
@ -5,7 +5,7 @@ module ActiveModel
|
||||
def setup
|
||||
@resource = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||
@serializer = ProfileSerializer.new(@resource)
|
||||
@adapter = ActiveModel::Serializer::Adapter.create(@serializer)
|
||||
@adapter = ActiveModelSerializers::Adapter.create(@serializer)
|
||||
@serializable_resource = ActiveModel::SerializableResource.new(@resource)
|
||||
end
|
||||
|
||||
|
||||
@ -1,166 +0,0 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class AdapterForTest < ActiveSupport::TestCase
|
||||
UnknownAdapterError = ::ActiveModel::Serializer::Adapter::UnknownAdapterError
|
||||
|
||||
def setup
|
||||
@previous_adapter = ActiveModelSerializers.config.adapter
|
||||
end
|
||||
|
||||
def teardown
|
||||
ActiveModelSerializers.config.adapter = @previous_adapter
|
||||
end
|
||||
|
||||
def test_returns_default_adapter
|
||||
adapter = ActiveModel::Serializer.adapter
|
||||
assert_equal ActiveModel::Serializer::Adapter::Attributes, adapter
|
||||
end
|
||||
|
||||
def test_overwrite_adapter_with_symbol
|
||||
ActiveModelSerializers.config.adapter = :null
|
||||
|
||||
adapter = ActiveModel::Serializer.adapter
|
||||
assert_equal ActiveModel::Serializer::Adapter::Null, adapter
|
||||
ensure
|
||||
ActiveModelSerializers.config.adapter = @previous_adapter
|
||||
end
|
||||
|
||||
def test_overwrite_adapter_with_class
|
||||
ActiveModelSerializers.config.adapter = ActiveModel::Serializer::Adapter::Null
|
||||
|
||||
adapter = ActiveModel::Serializer.adapter
|
||||
assert_equal ActiveModel::Serializer::Adapter::Null, adapter
|
||||
end
|
||||
|
||||
def test_raises_exception_if_invalid_symbol_given
|
||||
ActiveModelSerializers.config.adapter = :unknown
|
||||
|
||||
assert_raises UnknownAdapterError do
|
||||
ActiveModel::Serializer.adapter
|
||||
end
|
||||
end
|
||||
|
||||
def test_raises_exception_if_it_does_not_know_hot_to_infer_adapter
|
||||
ActiveModelSerializers.config.adapter = 42
|
||||
|
||||
assert_raises UnknownAdapterError do
|
||||
ActiveModel::Serializer.adapter
|
||||
end
|
||||
end
|
||||
|
||||
def test_adapter_class_for_known_adapter
|
||||
klass = ActiveModel::Serializer::Adapter.adapter_class(:json_api)
|
||||
assert_equal ActiveModel::Serializer::Adapter::JsonApi, klass
|
||||
end
|
||||
|
||||
def test_adapter_class_for_unknown_adapter
|
||||
assert_raises UnknownAdapterError do
|
||||
ActiveModel::Serializer::Adapter.adapter_class(:json_simple)
|
||||
end
|
||||
end
|
||||
|
||||
def test_adapter_map
|
||||
expected_adapter_map = {
|
||||
'null'.freeze => ActiveModel::Serializer::Adapter::Null,
|
||||
'json'.freeze => ActiveModel::Serializer::Adapter::Json,
|
||||
'attributes'.freeze => ActiveModel::Serializer::Adapter::Attributes,
|
||||
'json_api'.freeze => ActiveModel::Serializer::Adapter::JsonApi
|
||||
}
|
||||
actual = ActiveModel::Serializer::Adapter.adapter_map
|
||||
assert_equal actual, expected_adapter_map
|
||||
end
|
||||
|
||||
def test_adapters
|
||||
assert_equal ActiveModel::Serializer::Adapter.adapters.sort, [
|
||||
'attributes'.freeze,
|
||||
'json'.freeze,
|
||||
'json_api'.freeze,
|
||||
'null'.freeze
|
||||
]
|
||||
end
|
||||
|
||||
def test_lookup_adapter_by_string_name
|
||||
assert_equal ActiveModel::Serializer::Adapter.lookup('json'.freeze), ActiveModel::Serializer::Adapter::Json
|
||||
end
|
||||
|
||||
def test_lookup_adapter_by_symbol_name
|
||||
assert_equal ActiveModel::Serializer::Adapter.lookup(:json), ActiveModel::Serializer::Adapter::Json
|
||||
end
|
||||
|
||||
def test_lookup_adapter_by_class
|
||||
klass = ActiveModel::Serializer::Adapter::Json
|
||||
assert_equal ActiveModel::Serializer::Adapter.lookup(klass), klass
|
||||
end
|
||||
|
||||
def test_lookup_adapter_from_environment_registers_adapter
|
||||
ActiveModel::Serializer::Adapter.const_set(:AdapterFromEnvironment, Class.new)
|
||||
klass = ::ActiveModel::Serializer::Adapter::AdapterFromEnvironment
|
||||
name = 'adapter_from_environment'.freeze
|
||||
assert_equal ActiveModel::Serializer::Adapter.lookup(name), klass
|
||||
assert ActiveModel::Serializer::Adapter.adapters.include?(name)
|
||||
ensure
|
||||
ActiveModel::Serializer::Adapter.adapter_map.delete(name)
|
||||
ActiveModel::Serializer::Adapter.send(:remove_const, :AdapterFromEnvironment)
|
||||
end
|
||||
|
||||
def test_lookup_adapter_for_unknown_name
|
||||
assert_raises UnknownAdapterError do
|
||||
ActiveModel::Serializer::Adapter.lookup(:json_simple)
|
||||
end
|
||||
end
|
||||
|
||||
def test_adapter
|
||||
assert_equal ActiveModelSerializers.config.adapter, :attributes
|
||||
assert_equal ActiveModel::Serializer.adapter, ActiveModel::Serializer::Adapter::Attributes
|
||||
end
|
||||
|
||||
def test_register_adapter
|
||||
new_adapter_name = :foo
|
||||
new_adapter_klass = Class.new
|
||||
ActiveModel::Serializer::Adapter.register(new_adapter_name, new_adapter_klass)
|
||||
assert ActiveModel::Serializer::Adapter.adapters.include?('foo'.freeze)
|
||||
assert ActiveModel::Serializer::Adapter.lookup(:foo), new_adapter_klass
|
||||
ensure
|
||||
ActiveModel::Serializer::Adapter.adapter_map.delete(new_adapter_name.to_s)
|
||||
end
|
||||
|
||||
def test_inherited_adapter_hooks_register_adapter
|
||||
Object.const_set(:MyAdapter, Class.new)
|
||||
my_adapter = MyAdapter
|
||||
ActiveModel::Serializer::Adapter::Base.inherited(my_adapter)
|
||||
assert_equal ActiveModel::Serializer::Adapter.lookup(:my_adapter), my_adapter
|
||||
ensure
|
||||
ActiveModel::Serializer::Adapter.adapter_map.delete('my_adapter'.freeze)
|
||||
Object.send(:remove_const, :MyAdapter)
|
||||
end
|
||||
|
||||
def test_inherited_adapter_hooks_register_namespaced_adapter
|
||||
Object.const_set(:MyNamespace, Module.new)
|
||||
MyNamespace.const_set(:MyAdapter, Class.new)
|
||||
my_adapter = MyNamespace::MyAdapter
|
||||
ActiveModel::Serializer::Adapter::Base.inherited(my_adapter)
|
||||
assert_equal ActiveModel::Serializer::Adapter.lookup(:'my_namespace/my_adapter'), my_adapter
|
||||
ensure
|
||||
ActiveModel::Serializer::Adapter.adapter_map.delete('my_namespace/my_adapter'.freeze)
|
||||
MyNamespace.send(:remove_const, :MyAdapter)
|
||||
Object.send(:remove_const, :MyNamespace)
|
||||
end
|
||||
|
||||
def test_inherited_adapter_hooks_register_subclass_of_registered_adapter
|
||||
Object.const_set(:MyAdapter, Class.new)
|
||||
my_adapter = MyAdapter
|
||||
Object.const_set(:MySubclassedAdapter, Class.new(MyAdapter))
|
||||
my_subclassed_adapter = MySubclassedAdapter
|
||||
ActiveModel::Serializer::Adapter::Base.inherited(my_adapter)
|
||||
ActiveModel::Serializer::Adapter::Base.inherited(my_subclassed_adapter)
|
||||
assert_equal ActiveModel::Serializer::Adapter.lookup(:my_adapter), my_adapter
|
||||
assert_equal ActiveModel::Serializer::Adapter.lookup(:my_subclassed_adapter), my_subclassed_adapter
|
||||
ensure
|
||||
ActiveModel::Serializer::Adapter.adapter_map.delete('my_adapter'.freeze)
|
||||
ActiveModel::Serializer::Adapter.adapter_map.delete('my_subclassed_adapter'.freeze)
|
||||
Object.send(:remove_const, :MyAdapter)
|
||||
Object.send(:remove_const, :MySubclassedAdapter)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -14,14 +14,14 @@ module ActiveModel
|
||||
end
|
||||
|
||||
def test_json_serializable_hash
|
||||
adapter = ActiveModel::Serializer::Adapter::Json.new(@blog_serializer)
|
||||
adapter = ActiveModelSerializers::Adapter::Json.new(@blog_serializer)
|
||||
assert_equal({ blog: { id: 1, title: 'AMS Hints' } }, adapter.serializable_hash)
|
||||
end
|
||||
|
||||
def test_attribute_inheritance_with_key
|
||||
inherited_klass = Class.new(AlternateBlogSerializer)
|
||||
blog_serializer = inherited_klass.new(@blog)
|
||||
adapter = ActiveModel::Serializer::Adapter::Attributes.new(blog_serializer)
|
||||
adapter = ActiveModelSerializers::Adapter::Attributes.new(blog_serializer)
|
||||
assert_equal({ :id => 1, :title => 'AMS Hints' }, adapter.serializable_hash)
|
||||
end
|
||||
|
||||
@ -39,7 +39,7 @@ module ActiveModel
|
||||
attribute :name, key: :id
|
||||
end
|
||||
|
||||
adapter = ActiveModel::Serializer::Adapter::Json.new(serializer.new(@blog))
|
||||
adapter = ActiveModelSerializers::Adapter::Json.new(serializer.new(@blog))
|
||||
assert_equal({ blog: { id: 'AMS Hints' } }, adapter.serializable_hash)
|
||||
end
|
||||
|
||||
@ -48,7 +48,7 @@ module ActiveModel
|
||||
attribute :name, key: :object
|
||||
end
|
||||
|
||||
adapter = ActiveModel::Serializer::Adapter::Json.new(serializer.new(@blog))
|
||||
adapter = ActiveModelSerializers::Adapter::Json.new(serializer.new(@blog))
|
||||
assert_equal({ blog: { object: 'AMS Hints' } }, adapter.serializable_hash)
|
||||
end
|
||||
|
||||
@ -60,10 +60,10 @@ module ActiveModel
|
||||
attributes :type
|
||||
end
|
||||
|
||||
adapter = ActiveModel::Serializer::Adapter::Json.new(attribute_serializer.new(@blog))
|
||||
adapter = ActiveModelSerializers::Adapter::Json.new(attribute_serializer.new(@blog))
|
||||
assert_equal({ blog: { type: 1 } }, adapter.serializable_hash)
|
||||
|
||||
adapter = ActiveModel::Serializer::Adapter::Json.new(attributes_serializer.new(@blog))
|
||||
adapter = ActiveModelSerializers::Adapter::Json.new(attributes_serializer.new(@blog))
|
||||
assert_equal({ blog: { type: 'stuff' } }, adapter.serializable_hash)
|
||||
end
|
||||
|
||||
|
||||
@ -1,241 +1,236 @@
|
||||
require 'test_helper'
|
||||
require 'tmpdir'
|
||||
require 'tempfile'
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class CacheTest < ActiveSupport::TestCase
|
||||
include ActiveSupport::Testing::Stream
|
||||
module ActiveModelSerializers
|
||||
class CacheTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
ActionController::Base.cache_store.clear
|
||||
@comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@post = Post.new(title: 'New Post', body: 'Body')
|
||||
@bio = Bio.new(id: 1, content: 'AMS Contributor')
|
||||
@author = Author.new(name: 'Joao M. D. Moura')
|
||||
@blog = Blog.new(id: 999, name: 'Custom blog', writer: @author, articles: [])
|
||||
@role = Role.new(name: 'Great Author')
|
||||
@location = Location.new(lat: '-23.550520', lng: '-46.633309')
|
||||
@place = Place.new(name: 'Amazing Place')
|
||||
@author.posts = [@post]
|
||||
@author.roles = [@role]
|
||||
@role.author = @author
|
||||
@author.bio = @bio
|
||||
@bio.author = @author
|
||||
@post.comments = [@comment]
|
||||
@post.author = @author
|
||||
@comment.post = @post
|
||||
@comment.author = @author
|
||||
@post.blog = @blog
|
||||
@location.place = @place
|
||||
|
||||
def setup
|
||||
ActionController::Base.cache_store.clear
|
||||
@comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||
@post = Post.new(title: 'New Post', body: 'Body')
|
||||
@bio = Bio.new(id: 1, content: 'AMS Contributor')
|
||||
@author = Author.new(name: 'Joao M. D. Moura')
|
||||
@blog = Blog.new(id: 999, name: 'Custom blog', writer: @author, articles: [])
|
||||
@role = Role.new(name: 'Great Author')
|
||||
@location = Location.new(lat: '-23.550520', lng: '-46.633309')
|
||||
@place = Place.new(name: 'Amazing Place')
|
||||
@author.posts = [@post]
|
||||
@author.roles = [@role]
|
||||
@role.author = @author
|
||||
@author.bio = @bio
|
||||
@bio.author = @author
|
||||
@post.comments = [@comment]
|
||||
@post.author = @author
|
||||
@comment.post = @post
|
||||
@comment.author = @author
|
||||
@post.blog = @blog
|
||||
@location.place = @place
|
||||
@location_serializer = LocationSerializer.new(@location)
|
||||
@bio_serializer = BioSerializer.new(@bio)
|
||||
@role_serializer = RoleSerializer.new(@role)
|
||||
@post_serializer = PostSerializer.new(@post)
|
||||
@author_serializer = AuthorSerializer.new(@author)
|
||||
@comment_serializer = CommentSerializer.new(@comment)
|
||||
@blog_serializer = BlogSerializer.new(@blog)
|
||||
end
|
||||
|
||||
@location_serializer = LocationSerializer.new(@location)
|
||||
@bio_serializer = BioSerializer.new(@bio)
|
||||
@role_serializer = RoleSerializer.new(@role)
|
||||
@post_serializer = PostSerializer.new(@post)
|
||||
@author_serializer = AuthorSerializer.new(@author)
|
||||
@comment_serializer = CommentSerializer.new(@comment)
|
||||
@blog_serializer = BlogSerializer.new(@blog)
|
||||
def test_inherited_cache_configuration
|
||||
inherited_serializer = Class.new(PostSerializer)
|
||||
|
||||
assert_equal PostSerializer._cache_key, inherited_serializer._cache_key
|
||||
assert_equal PostSerializer._cache_options, inherited_serializer._cache_options
|
||||
end
|
||||
|
||||
def test_override_cache_configuration
|
||||
inherited_serializer = Class.new(PostSerializer) do
|
||||
cache key: 'new-key'
|
||||
end
|
||||
|
||||
def test_inherited_cache_configuration
|
||||
inherited_serializer = Class.new(PostSerializer)
|
||||
assert_equal PostSerializer._cache_key, 'post'
|
||||
assert_equal inherited_serializer._cache_key, 'new-key'
|
||||
end
|
||||
|
||||
assert_equal PostSerializer._cache_key, inherited_serializer._cache_key
|
||||
assert_equal PostSerializer._cache_options, inherited_serializer._cache_options
|
||||
def test_cache_definition
|
||||
assert_equal(ActionController::Base.cache_store, @post_serializer.class._cache)
|
||||
assert_equal(ActionController::Base.cache_store, @author_serializer.class._cache)
|
||||
assert_equal(ActionController::Base.cache_store, @comment_serializer.class._cache)
|
||||
end
|
||||
|
||||
def test_cache_key_definition
|
||||
assert_equal('post', @post_serializer.class._cache_key)
|
||||
assert_equal('writer', @author_serializer.class._cache_key)
|
||||
assert_equal(nil, @comment_serializer.class._cache_key)
|
||||
end
|
||||
|
||||
def test_cache_key_interpolation_with_updated_at
|
||||
render_object_with_cache(@author)
|
||||
assert_equal(nil, ActionController::Base.cache_store.fetch(@author.cache_key))
|
||||
assert_equal(@author_serializer.attributes.to_json, ActionController::Base.cache_store.fetch("#{@author_serializer.class._cache_key}/#{@author_serializer.object.id}-#{@author_serializer.object.updated_at.strftime("%Y%m%d%H%M%S%9N")}").to_json)
|
||||
end
|
||||
|
||||
def test_default_cache_key_fallback
|
||||
render_object_with_cache(@comment)
|
||||
assert_equal(@comment_serializer.attributes.to_json, ActionController::Base.cache_store.fetch(@comment.cache_key).to_json)
|
||||
end
|
||||
|
||||
def test_cache_options_definition
|
||||
assert_equal({ expires_in: 0.1, skip_digest: true }, @post_serializer.class._cache_options)
|
||||
assert_equal(nil, @blog_serializer.class._cache_options)
|
||||
assert_equal({ expires_in: 1.day, skip_digest: true }, @comment_serializer.class._cache_options)
|
||||
end
|
||||
|
||||
def test_fragment_cache_definition
|
||||
assert_equal([:name], @role_serializer.class._cache_only)
|
||||
assert_equal([:content], @bio_serializer.class._cache_except)
|
||||
end
|
||||
|
||||
def test_associations_separately_cache
|
||||
ActionController::Base.cache_store.clear
|
||||
assert_equal(nil, ActionController::Base.cache_store.fetch(@post.cache_key))
|
||||
assert_equal(nil, ActionController::Base.cache_store.fetch(@comment.cache_key))
|
||||
|
||||
Timecop.freeze(Time.now) do
|
||||
render_object_with_cache(@post)
|
||||
|
||||
assert_equal(@post_serializer.attributes, ActionController::Base.cache_store.fetch(@post.cache_key))
|
||||
assert_equal(@comment_serializer.attributes, ActionController::Base.cache_store.fetch(@comment.cache_key))
|
||||
end
|
||||
end
|
||||
|
||||
def test_override_cache_configuration
|
||||
inherited_serializer = Class.new(PostSerializer) do
|
||||
cache key: 'new-key'
|
||||
end
|
||||
def test_associations_cache_when_updated
|
||||
# Clean the Cache
|
||||
ActionController::Base.cache_store.clear
|
||||
|
||||
assert_equal PostSerializer._cache_key, 'post'
|
||||
assert_equal inherited_serializer._cache_key, 'new-key'
|
||||
Timecop.freeze(Time.now) do
|
||||
# Generate a new Cache of Post object and each objects related to it.
|
||||
render_object_with_cache(@post)
|
||||
|
||||
# Check if it cached the objects separately
|
||||
assert_equal(@post_serializer.attributes, ActionController::Base.cache_store.fetch(@post.cache_key))
|
||||
assert_equal(@comment_serializer.attributes, ActionController::Base.cache_store.fetch(@comment.cache_key))
|
||||
|
||||
# Simulating update on comments relationship with Post
|
||||
new_comment = Comment.new(id: 2, body: 'ZOMG A NEW COMMENT')
|
||||
new_comment_serializer = CommentSerializer.new(new_comment)
|
||||
@post.comments = [new_comment]
|
||||
|
||||
# Ask for the serialized object
|
||||
render_object_with_cache(@post)
|
||||
|
||||
# Check if the the new comment was cached
|
||||
assert_equal(new_comment_serializer.attributes, ActionController::Base.cache_store.fetch(new_comment.cache_key))
|
||||
assert_equal(@post_serializer.attributes, ActionController::Base.cache_store.fetch(@post.cache_key))
|
||||
end
|
||||
end
|
||||
|
||||
def test_cache_definition
|
||||
assert_equal(ActionController::Base.cache_store, @post_serializer.class._cache)
|
||||
assert_equal(ActionController::Base.cache_store, @author_serializer.class._cache)
|
||||
assert_equal(ActionController::Base.cache_store, @comment_serializer.class._cache)
|
||||
end
|
||||
def test_fragment_fetch_with_virtual_associations
|
||||
expected_result = {
|
||||
id: @location.id,
|
||||
lat: @location.lat,
|
||||
lng: @location.lng,
|
||||
place: 'Nowhere'
|
||||
}
|
||||
|
||||
def test_cache_key_definition
|
||||
assert_equal('post', @post_serializer.class._cache_key)
|
||||
assert_equal('writer', @author_serializer.class._cache_key)
|
||||
assert_equal(nil, @comment_serializer.class._cache_key)
|
||||
end
|
||||
hash = render_object_with_cache(@location)
|
||||
|
||||
def test_cache_key_interpolation_with_updated_at
|
||||
render_object_with_cache(@author)
|
||||
assert_equal(nil, ActionController::Base.cache_store.fetch(@author.cache_key))
|
||||
assert_equal(@author_serializer.attributes.to_json, ActionController::Base.cache_store.fetch("#{@author_serializer.class._cache_key}/#{@author_serializer.object.id}-#{@author_serializer.object.updated_at.strftime("%Y%m%d%H%M%S%9N")}").to_json)
|
||||
end
|
||||
assert_equal(hash, expected_result)
|
||||
assert_equal({ place: 'Nowhere' }, ActionController::Base.cache_store.fetch(@location.cache_key))
|
||||
end
|
||||
|
||||
def test_default_cache_key_fallback
|
||||
def test_uses_file_digest_in_cache_key
|
||||
render_object_with_cache(@blog)
|
||||
assert_equal(@blog_serializer.attributes, ActionController::Base.cache_store.fetch(@blog.cache_key_with_digest))
|
||||
end
|
||||
|
||||
def test_cache_digest_definition
|
||||
assert_equal(::Model::FILE_DIGEST, @post_serializer.class._cache_digest)
|
||||
end
|
||||
|
||||
def test_object_cache_keys
|
||||
serializer = ActiveModel::Serializer::CollectionSerializer.new([@comment, @comment])
|
||||
include_tree = ActiveModel::Serializer::IncludeTree.from_include_args('*')
|
||||
|
||||
actual = Adapter::CachedSerializer.object_cache_keys(serializer, include_tree)
|
||||
|
||||
assert_equal actual.size, 3
|
||||
assert actual.any? { |key| key == 'comment/1' }
|
||||
assert actual.any? { |key| key =~ %r{post/post-\d+} }
|
||||
assert actual.any? { |key| key =~ %r{writer/author-\d+} }
|
||||
end
|
||||
|
||||
def test_cached_attributes
|
||||
serializer = ActiveModel::Serializer::CollectionSerializer.new([@comment, @comment])
|
||||
|
||||
Timecop.freeze(Time.now) do
|
||||
render_object_with_cache(@comment)
|
||||
assert_equal(@comment_serializer.attributes.to_json, ActionController::Base.cache_store.fetch(@comment.cache_key).to_json)
|
||||
|
||||
attributes = Adapter::Attributes.new(serializer)
|
||||
attributes.send(:cache_attributes)
|
||||
cached_attributes = attributes.instance_variable_get(:@cached_attributes)
|
||||
|
||||
assert_equal cached_attributes[@comment.cache_key], Comment.new(id: 1, body: 'ZOMG A COMMENT').attributes
|
||||
assert_equal cached_attributes[@comment.post.cache_key], Post.new(id: 'post', title: 'New Post', body: 'Body').attributes
|
||||
|
||||
writer = @comment.post.blog.writer
|
||||
writer_cache_key = "writer/#{writer.id}-#{writer.updated_at.strftime("%Y%m%d%H%M%S%9N")}"
|
||||
|
||||
assert_equal cached_attributes[writer_cache_key], Author.new(id: 'author', name: 'Joao M. D. Moura').attributes
|
||||
end
|
||||
end
|
||||
|
||||
def test_cache_options_definition
|
||||
assert_equal({ expires_in: 0.1, skip_digest: true }, @post_serializer.class._cache_options)
|
||||
assert_equal(nil, @blog_serializer.class._cache_options)
|
||||
assert_equal({ expires_in: 1.day, skip_digest: true }, @comment_serializer.class._cache_options)
|
||||
def test_serializer_file_path_on_nix
|
||||
path = '/Users/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb'
|
||||
caller_line = "#{path}:1:in `<top (required)>'"
|
||||
assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
|
||||
end
|
||||
|
||||
def test_serializer_file_path_on_windows
|
||||
path = 'c:/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb'
|
||||
caller_line = "#{path}:1:in `<top (required)>'"
|
||||
assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
|
||||
end
|
||||
|
||||
def test_serializer_file_path_with_space
|
||||
path = '/Users/git/ember js/ember-crm-backend/app/serializers/lead_serializer.rb'
|
||||
caller_line = "#{path}:1:in `<top (required)>'"
|
||||
assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
|
||||
end
|
||||
|
||||
def test_serializer_file_path_with_submatch
|
||||
# The submatch in the path ensures we're using a correctly greedy regexp.
|
||||
path = '/Users/git/ember js/ember:123:in x/app/serializers/lead_serializer.rb'
|
||||
caller_line = "#{path}:1:in `<top (required)>'"
|
||||
assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
|
||||
end
|
||||
|
||||
def test_digest_caller_file
|
||||
contents = "puts 'AMS rocks'!"
|
||||
dir = Dir.mktmpdir('space char')
|
||||
file = Tempfile.new('some_ruby.rb', dir)
|
||||
file.write(contents)
|
||||
path = file.path
|
||||
caller_line = "#{path}:1:in `<top (required)>'"
|
||||
file.close
|
||||
assert_equal ActiveModel::Serializer.digest_caller_file(caller_line), Digest::MD5.hexdigest(contents)
|
||||
ensure
|
||||
file.unlink
|
||||
FileUtils.remove_entry dir
|
||||
end
|
||||
|
||||
def test_warn_on_serializer_not_defined_in_file
|
||||
called = false
|
||||
serializer = Class.new(ActiveModel::Serializer)
|
||||
assert_output(nil, /_cache_digest/) do
|
||||
serializer.digest_caller_file('')
|
||||
called = true
|
||||
end
|
||||
assert called
|
||||
end
|
||||
|
||||
def test_fragment_cache_definition
|
||||
assert_equal([:name], @role_serializer.class._cache_only)
|
||||
assert_equal([:content], @bio_serializer.class._cache_except)
|
||||
end
|
||||
private
|
||||
|
||||
def test_associations_separately_cache
|
||||
ActionController::Base.cache_store.clear
|
||||
assert_equal(nil, ActionController::Base.cache_store.fetch(@post.cache_key))
|
||||
assert_equal(nil, ActionController::Base.cache_store.fetch(@comment.cache_key))
|
||||
|
||||
Timecop.freeze(Time.now) do
|
||||
render_object_with_cache(@post)
|
||||
|
||||
assert_equal(@post_serializer.attributes, ActionController::Base.cache_store.fetch(@post.cache_key))
|
||||
assert_equal(@comment_serializer.attributes, ActionController::Base.cache_store.fetch(@comment.cache_key))
|
||||
end
|
||||
end
|
||||
|
||||
def test_associations_cache_when_updated
|
||||
# Clean the Cache
|
||||
ActionController::Base.cache_store.clear
|
||||
|
||||
Timecop.freeze(Time.now) do
|
||||
# Generate a new Cache of Post object and each objects related to it.
|
||||
render_object_with_cache(@post)
|
||||
|
||||
# Check if it cached the objects separately
|
||||
assert_equal(@post_serializer.attributes, ActionController::Base.cache_store.fetch(@post.cache_key))
|
||||
assert_equal(@comment_serializer.attributes, ActionController::Base.cache_store.fetch(@comment.cache_key))
|
||||
|
||||
# Simulating update on comments relationship with Post
|
||||
new_comment = Comment.new(id: 2, body: 'ZOMG A NEW COMMENT')
|
||||
new_comment_serializer = CommentSerializer.new(new_comment)
|
||||
@post.comments = [new_comment]
|
||||
|
||||
# Ask for the serialized object
|
||||
render_object_with_cache(@post)
|
||||
|
||||
# Check if the the new comment was cached
|
||||
assert_equal(new_comment_serializer.attributes, ActionController::Base.cache_store.fetch(new_comment.cache_key))
|
||||
assert_equal(@post_serializer.attributes, ActionController::Base.cache_store.fetch(@post.cache_key))
|
||||
end
|
||||
end
|
||||
|
||||
def test_fragment_fetch_with_virtual_associations
|
||||
expected_result = {
|
||||
id: @location.id,
|
||||
lat: @location.lat,
|
||||
lng: @location.lng,
|
||||
place: 'Nowhere'
|
||||
}
|
||||
|
||||
hash = render_object_with_cache(@location)
|
||||
|
||||
assert_equal(hash, expected_result)
|
||||
assert_equal({ place: 'Nowhere' }, ActionController::Base.cache_store.fetch(@location.cache_key))
|
||||
end
|
||||
|
||||
def test_uses_file_digest_in_cache_key
|
||||
render_object_with_cache(@blog)
|
||||
assert_equal(@blog_serializer.attributes, ActionController::Base.cache_store.fetch(@blog.cache_key_with_digest))
|
||||
end
|
||||
|
||||
def test_cache_digest_definition
|
||||
assert_equal(::Model::FILE_DIGEST, @post_serializer.class._cache_digest)
|
||||
end
|
||||
|
||||
def test_object_cache_keys
|
||||
serializer = CollectionSerializer.new([@comment, @comment])
|
||||
include_tree = IncludeTree.from_include_args('*')
|
||||
|
||||
actual = Serializer::Adapter::CachedSerializer.object_cache_keys(serializer, include_tree)
|
||||
|
||||
assert_equal actual.size, 3
|
||||
assert actual.any? { |key| key == 'comment/1' }
|
||||
assert actual.any? { |key| key =~ %r{post/post-\d+} }
|
||||
assert actual.any? { |key| key =~ %r{writer/author-\d+} }
|
||||
end
|
||||
|
||||
def test_cached_attributes
|
||||
serializer = CollectionSerializer.new([@comment, @comment])
|
||||
|
||||
Timecop.freeze(Time.now) do
|
||||
render_object_with_cache(@comment)
|
||||
|
||||
attributes = ActiveModel::Serializer::Adapter::Attributes.new(serializer)
|
||||
attributes.send(:cache_attributes)
|
||||
cached_attributes = attributes.instance_variable_get(:@cached_attributes)
|
||||
|
||||
assert_equal cached_attributes[@comment.cache_key], Comment.new(id: 1, body: 'ZOMG A COMMENT').attributes
|
||||
assert_equal cached_attributes[@comment.post.cache_key], Post.new(id: 'post', title: 'New Post', body: 'Body').attributes
|
||||
|
||||
writer = @comment.post.blog.writer
|
||||
writer_cache_key = "writer/#{writer.id}-#{writer.updated_at.strftime("%Y%m%d%H%M%S%9N")}"
|
||||
|
||||
assert_equal cached_attributes[writer_cache_key], Author.new(id: 'author', name: 'Joao M. D. Moura').attributes
|
||||
end
|
||||
end
|
||||
|
||||
def test_serializer_file_path_on_nix
|
||||
path = '/Users/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb'
|
||||
caller_line = "#{path}:1:in `<top (required)>'"
|
||||
assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
|
||||
end
|
||||
|
||||
def test_serializer_file_path_on_windows
|
||||
path = 'c:/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb'
|
||||
caller_line = "#{path}:1:in `<top (required)>'"
|
||||
assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
|
||||
end
|
||||
|
||||
def test_serializer_file_path_with_space
|
||||
path = '/Users/git/ember js/ember-crm-backend/app/serializers/lead_serializer.rb'
|
||||
caller_line = "#{path}:1:in `<top (required)>'"
|
||||
assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
|
||||
end
|
||||
|
||||
def test_serializer_file_path_with_submatch
|
||||
# The submatch in the path ensures we're using a correctly greedy regexp.
|
||||
path = '/Users/git/ember js/ember:123:in x/app/serializers/lead_serializer.rb'
|
||||
caller_line = "#{path}:1:in `<top (required)>'"
|
||||
assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
|
||||
end
|
||||
|
||||
def test_digest_caller_file
|
||||
contents = "puts 'AMS rocks'!"
|
||||
dir = Dir.mktmpdir('space char')
|
||||
file = Tempfile.new('some_ruby.rb', dir)
|
||||
file.write(contents)
|
||||
path = file.path
|
||||
caller_line = "#{path}:1:in `<top (required)>'"
|
||||
file.close
|
||||
assert_equal ActiveModel::Serializer.digest_caller_file(caller_line), Digest::MD5.hexdigest(contents)
|
||||
ensure
|
||||
file.unlink
|
||||
FileUtils.remove_entry dir
|
||||
end
|
||||
|
||||
def test_warn_on_serializer_not_defined_in_file
|
||||
called = false
|
||||
serializer = Class.new(ActiveModel::Serializer)
|
||||
assert_match(/_cache_digest/, (capture(:stderr) do
|
||||
serializer.digest_caller_file('')
|
||||
called = true
|
||||
end))
|
||||
assert called
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def render_object_with_cache(obj)
|
||||
ActiveModel::SerializableResource.new(obj).serializable_hash
|
||||
end
|
||||
def render_object_with_cache(obj)
|
||||
ActiveModel::SerializableResource.new(obj).serializable_hash
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -1,81 +1,79 @@
|
||||
require 'test_helper'
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
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?
|
||||
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?
|
||||
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?
|
||||
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?
|
||||
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?
|
||||
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?
|
||||
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?
|
||||
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?
|
||||
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
|
||||
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)
|
||||
ActiveModel::Serializer::Adapter::CachedSerializer.new(serializer_instance)
|
||||
end
|
||||
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
|
||||
|
||||
@ -1,50 +0,0 @@
|
||||
# Use cleaner stream testing interface from Rails 5 if available
|
||||
# see https://github.com/rails/rails/blob/29959eb59d/activesupport/lib/active_support/testing/stream.rb
|
||||
begin
|
||||
require 'active_support/testing/stream'
|
||||
rescue LoadError
|
||||
require 'tempfile'
|
||||
module ActiveSupport
|
||||
module Testing
|
||||
module Stream #:nodoc:
|
||||
private
|
||||
|
||||
def silence_stream(stream)
|
||||
old_stream = stream.dup
|
||||
stream.reopen(IO::NULL)
|
||||
stream.sync = true
|
||||
yield
|
||||
ensure
|
||||
stream.reopen(old_stream)
|
||||
old_stream.close
|
||||
end
|
||||
|
||||
def quietly
|
||||
silence_stream(STDOUT) do
|
||||
silence_stream(STDERR) do
|
||||
yield
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def capture(stream)
|
||||
stream = stream.to_s
|
||||
captured_stream = Tempfile.new(stream)
|
||||
stream_io = eval("$#{stream}") # rubocop:disable Lint/Eval
|
||||
origin_stream = stream_io.dup
|
||||
stream_io.reopen(captured_stream)
|
||||
|
||||
yield
|
||||
|
||||
stream_io.rewind
|
||||
return captured_stream.read
|
||||
ensure
|
||||
captured_stream.close
|
||||
captured_stream.unlink
|
||||
stream_io.reopen(origin_stream)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -43,8 +43,6 @@ end
|
||||
require 'minitest/reporters'
|
||||
Minitest::Reporters.use!
|
||||
|
||||
require 'support/stream_capture'
|
||||
|
||||
require 'support/rails_app'
|
||||
|
||||
require 'support/test_case'
|
||||
|
||||
Loading…
Reference in New Issue
Block a user