Moved the adapter and adapter folder to active_model_serializers folder and changed the module namespace

Changed the namespace in adapters and folder to active_model_serializers from active_model::serializer

Changed namespace of adapters in serializers and other folders

Moved adapter_for_test file to active_model_serializers folder and changed namespace of adapter inside the test file

Require ActiveSupport's string/inflections

We depend on string/inflections to define String#underscore.

Refactor JsonApi adapter to avoid redundant computations.

Update readme.md to link to v0.10.0.rc4

changed namespace of adapter folder testcases

Changed all namespaces of adapter under active_moder_serializers

Namespaced IncludeTree which is from serializer module, so needed to namespace it properly

Fixed wrong namsepacing of fieldset

namespace change in deserializer json_api

Fixed the namespace for collection serializer when used inside adapter, changed namespace for adapter to new namespace which I had forgotten previously

Modified logging test and adapter test cases to make the testcases pass

Changed the yardoc links,as old links are not taking to documentation pages,proper links for 0.10,0.9 and 0.8 in rubydoc

Rubocop errors are fixed by underscore naming unused variables

Moved the require of adapter to serializable resource

Remoeved adapter dependency inside serializer and added warning to Serializer::adapter method

Fixed frament cache test which is calling Serializer.adapter

Changed the name of lookup_adapter_from_config to configured_adapter

Changed the docs which will show the new namespace of adapters

Rubocop fix
This commit is contained in:
bobba surendranath chowdary 2016-02-04 11:49:27 +05:30 committed by Benjamin Fleischer
parent f5ec8ed9d4
commit 252f9c4ae9
61 changed files with 2693 additions and 2764 deletions

View File

@ -3,6 +3,7 @@
Breaking changes:
Features:
Fixes:
- [#1488](https://github.com/rails-api/active_model_serializers/pull/1488) Require ActiveSupport's string inflections (@nate00)
Misc:
### v0.10.0.rc4 (2016/01/27 11:00 +00:00)

View File

@ -8,10 +8,12 @@
## Documentation
- [0.10 (master) Documentation](https://github.com/rails-api/active_model_serializers/tree/master)
- [![API Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/github/rails-api/active_model_serializers)
- [![API Docs](http://img.shields.io/badge/yard-docs-blue.svg)](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)
- [![API Docs](http://img.shields.io/badge/yard-docs-blue.svg)](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)
- [![API Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/github/rails-api/active_model_serializers/0-8-stable)
## About

View File

@ -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)

View File

@ -17,7 +17,7 @@ Payload (example):
```ruby
{
serializer: PostSerializer,
adapter: ActiveModel::Serializer::Adapter::Attributes
adapter: ActiveModelSerializers::Adapter::Attributes
}
```

View File

@ -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 `ActiveModelSerializers::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

View File

@ -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

View File

@ -21,7 +21,8 @@ module ActiveModel
include Caching
include Links
include Type
require 'active_model/serializer/adapter'
# Deprecated
require 'active_model_serializers/adapter'
# @param resource [ActiveRecord::Base, ActiveModelSerializers::Model]
# @return [ActiveModel::Serializer]
@ -40,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

View File

@ -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

View File

@ -1,66 +0,0 @@
module ActiveModel
class Serializer
module Adapter
class Attributes < Base
def initialize(serializer, options = {})
super
@include_tree = IncludeTree.from_include_args(options[:include] || '*')
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)
serializer.map { |s| Attributes.new(s, instance_options).serializable_hash(options) }
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)
cache_check(serializer) do
serializer.attributes(options[:fields])
end
end
end
end
end
end

View File

@ -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

View File

@ -1,45 +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_only && !@klass._cache_except || !@klass._cache_only && @klass._cache_except
end
def cache_key
parts = []
parts << object_cache_key
parts << @klass._cache_digest unless @klass._cache_options && @klass._cache_options[:skip_digest]
parts.join('/')
end
def object_cache_key
object_time_safe = @cached_serializer.object.updated_at
object_time_safe = object_time_safe.strftime('%Y%m%d%H%M%S%9N') if object_time_safe.respond_to?(:strftime)
(@klass._cache_key) ? "#{@klass._cache_key}/#{@cached_serializer.object.id}-#{object_time_safe}" : @cached_serializer.object.cache_key
end
end
end
end
end

View File

@ -1,111 +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)
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

View File

@ -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

View File

@ -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

View File

@ -1,223 +0,0 @@
module ActiveModel
class Serializer
module Adapter
class JsonApi < Base
extend ActiveSupport::Autoload
autoload :PaginationLinks
autoload :FragmentCache
autoload :Link
autoload :Deserialization
# 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 ||= {}
hash =
if serializer.respond_to?(:each)
serializable_hash_for_collection(options)
else
serializable_hash_for_single_resource
end
ApiObjects::JsonApi.add!(hash)
if instance_options[:links]
hash[:links] ||= {}
hash[:links].update(instance_options[:links])
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 serializable_hash_for_collection(options)
hash = { data: [] }
included = []
serializer.each do |s|
result = self.class.new(s, instance_options.merge(fieldset: fieldset)).serializable_hash(options)
hash[:data] << result[:data]
next unless result[:included]
included |= result[:included]
end
included.delete_if { |resource| hash[:data].include?(resource) }
hash[:included] = included if included.any?
if serializer.paginated?
hash[:links] ||= {}
hash[:links].update(pagination_links_for(serializer, options))
end
hash
end
def serializable_hash_for_single_resource
primary_data = resource_object_for(serializer)
hash = { data: primary_data }
included = included_resources(@include_tree, [primary_data])
hash[:included] = included if included.any?
hash
end
def resource_identifier_type_for(serializer)
return serializer._type if serializer._type
if ActiveModelSerializers.config.jsonapi_resource_type == :singular
serializer.object.class.model_name.singular
else
serializer.object.class.model_name.plural
end
end
def resource_identifier_id_for(serializer)
if serializer.respond_to?(:id)
serializer.id
else
serializer.object.id
end
end
def resource_identifier_for(serializer)
type = resource_identifier_type_for(serializer)
id = resource_identifier_id_for(serializer)
{ id: id.to_s, type: type }
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 = resource_identifier_for(serializer)
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
relationships = relationships_for(serializer)
resource_object[:relationships] = relationships if relationships.any?
links = links_for(serializer)
resource_object[:links] = links if links.any?
resource_object
end
def relationship_value_for(serializer, options = {})
if serializer.respond_to?(:each)
serializer.map { |s| resource_identifier_for(s) }
else
if options[:virtual_value]
options[:virtual_value]
elsif serializer && serializer.object
resource_identifier_for(serializer)
end
end
end
def relationships_for(serializer)
resource_type = resource_identifier_type_for(serializer)
requested_associations = fieldset.fields_for(resource_type) || '*'
include_tree = IncludeTree.from_include_args(requested_associations)
serializer.associations(include_tree).each_with_object({}) do |association, hash|
hash[association.key] = { data: relationship_value_for(association.serializer, association.options) }
end
end
def included_resources(include_tree, primary_data)
included = []
serializer.associations(include_tree).each do |association|
add_included_resources_for(association.serializer, include_tree[association.key], primary_data, included)
end
included
end
def add_included_resources_for(serializer, include_tree, primary_data, included)
if serializer.respond_to?(:each)
serializer.each { |s| add_included_resources_for(s, include_tree, primary_data, included) }
else
return unless serializer && serializer.object
resource_object = resource_object_for(serializer)
return if included.include?(resource_object) || primary_data.include?(resource_object)
included.push(resource_object)
serializer.associations(include_tree).each do |association|
add_included_resources_for(association.serializer, include_tree[association.key], primary_data, included)
end
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
end
end
end
end

View File

@ -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

View File

@ -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

View File

@ -1,44 +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 = { href: @href }
hash.merge!(meta: @meta) if @meta
hash
end
protected
attr_reader :object, :scope
end
end
end
end
end

View File

@ -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

View File

@ -1,11 +0,0 @@
module ActiveModel
class Serializer
module Adapter
class Null < Base
def serializable_hash(options = nil)
{}
end
end
end
end
end

View File

@ -1,6 +1,7 @@
require 'active_model'
require 'active_support'
require 'active_support/core_ext/object/with_options'
require 'active_support/core_ext/string/inflections'
module ActiveModelSerializers
extend ActiveSupport::Autoload
autoload :Model

View 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

View File

@ -0,0 +1,64 @@
module ActiveModelSerializers
module Adapter
class Attributes < Base
def initialize(serializer, options = {})
super
@include_tree = ActiveModel::Serializer::IncludeTree.from_include_args(options[:include] || '*')
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)
serializer.map { |s| Attributes.new(s, instance_options).serializable_hash(options) }
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)
cache_check(serializer) do
serializer.attributes(options[:fields])
end
end
end
end
end

View 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

View File

@ -0,0 +1,43 @@
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_only && !@klass._cache_except || !@klass._cache_only && @klass._cache_except
end
def cache_key
parts = []
parts << object_cache_key
parts << @klass._cache_digest unless @klass._cache_options && @klass._cache_options[:skip_digest]
parts.join('/')
end
def object_cache_key
object_time_safe = @cached_serializer.object.updated_at
object_time_safe = object_time_safe.strftime('%Y%m%d%H%M%S%9N') if object_time_safe.respond_to?(:strftime)
(@klass._cache_key) ? "#{@klass._cache_key}/#{@cached_serializer.object.id}-#{object_time_safe}" : @cached_serializer.object.cache_key
end
end
end
end

View File

@ -0,0 +1,109 @@
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)
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

View 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

View 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

View File

@ -0,0 +1,208 @@
module ActiveModelSerializers
module Adapter
class JsonApi < Base
extend ActiveSupport::Autoload
autoload :PaginationLinks
autoload :FragmentCache
autoload :Link
autoload :Deserialization
# 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 = resource_identifier_for(serializer)
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 resource_identifier_type_for(serializer)
return serializer._type if serializer._type
if ActiveModelSerializers.config.jsonapi_resource_type == :singular
serializer.object.class.model_name.singular
else
serializer.object.class.model_name.plural
end
end
def resource_identifier_id_for(serializer)
if serializer.respond_to?(:id)
serializer.id
else
serializer.object.id
end
end
def resource_identifier_for(serializer)
type = resource_identifier_type_for(serializer)
id = resource_identifier_id_for(serializer)
{ id: id.to_s, type: type }
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 = resource_identifier_for(serializer)
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
relationships = relationships_for(serializer)
resource_object[:relationships] = relationships if relationships.any?
links = links_for(serializer)
resource_object[:links] = links if links.any?
resource_object
end
def relationship_value_for(serializer, options = {})
if serializer.respond_to?(:each)
serializer.map { |s| resource_identifier_for(s) }
else
if options[:virtual_value]
options[:virtual_value]
elsif serializer && serializer.object
resource_identifier_for(serializer)
end
end
end
def relationships_for(serializer)
resource_type = resource_identifier_type_for(serializer)
requested_associations = fieldset.fields_for(resource_type) || '*'
include_tree = ActiveModel::Serializer::IncludeTree.from_include_args(requested_associations)
serializer.associations(include_tree).each_with_object({}) do |association, hash|
hash[association.key] = { data: relationship_value_for(association.serializer, association.options) }
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
end
end
end

View 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

View File

@ -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

View File

@ -0,0 +1,42 @@
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 = { href: @href }
hash.merge!(meta: @meta) if @meta
hash
end
protected
attr_reader :object, :scope
end
end
end
end

View File

@ -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

View 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

View File

@ -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

View File

@ -0,0 +1,164 @@
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_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_class
ActiveModelSerializers.config.adapter = ActiveModelSerializers::Adapter::Null
adapter = ActiveModelSerializers::Adapter.configured_adapter
assert_equal ActiveModelSerializers::Adapter::Null, adapter
end
def test_raises_exception_if_invalid_symbol_given
ActiveModelSerializers.config.adapter = :unknown
assert_raises UnknownAdapterError do
ActiveModelSerializers::Adapter.configured_adapter
end
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
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

View File

@ -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

View File

@ -1,36 +1,34 @@
require 'test_helper'
module ActiveModel
class Serializer
module Adapter
class FragmentCacheTest < ActiveSupport::TestCase
def setup
super
@spam = Spam::UnrelatedLink.new(id: 'spam-id-1')
@author = Author.new(name: 'Joao M. D. Moura')
@role = Role.new(name: 'Great Author', description: nil)
@role.author = [@author]
@role_serializer = RoleSerializer.new(@role)
@spam_serializer = Spam::UnrelatedLinkSerializer.new(@spam)
@role_hash = FragmentCache.new(RoleSerializer.adapter.new(@role_serializer), @role_serializer, {})
@spam_hash = FragmentCache.new(Spam::UnrelatedLinkSerializer.adapter.new(@spam_serializer), @spam_serializer, {})
end
module ActiveModelSerializers
module Adapter
class FragmentCacheTest < ActiveSupport::TestCase
def setup
super
@spam = Spam::UnrelatedLink.new(id: 'spam-id-1')
@author = Author.new(name: 'Joao M. D. Moura')
@role = Role.new(name: 'Great Author', description: nil)
@role.author = [@author]
@role_serializer = RoleSerializer.new(@role)
@spam_serializer = Spam::UnrelatedLinkSerializer.new(@spam)
@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
end
end

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,37 +1,35 @@
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
end
end

View File

@ -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

View File

@ -1,66 +1,64 @@
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)
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)
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_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

View File

@ -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

View File

@ -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

View File

@ -1,69 +1,67 @@
require 'test_helper'
module ActiveModel
class Serializer
module Adapter
class JsonApi
class ResourceTypeConfigTest < ActiveSupport::TestCase
class ProfileTypeSerializer < ActiveModel::Serializer
attributes :name
type 'profile'
end
module ActiveModelSerializers
module Adapter
class JsonApi
class ResourceTypeConfigTest < ActiveSupport::TestCase
class ProfileTypeSerializer < ActiveModel::Serializer
attributes :name
type 'profile'
end
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 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 with_jsonapi_resource_type type
old_type = ActiveModelSerializers.config.jsonapi_resource_type
ActiveModelSerializers.config.jsonapi_resource_type = type
yield
ensure
ActiveModelSerializers.config.jsonapi_resource_type = old_type
end
def with_jsonapi_resource_type type
old_type = ActiveModelSerializers.config.jsonapi_resource_type
ActiveModelSerializers.config.jsonapi_resource_type = type
yield
ensure
ActiveModelSerializers.config.jsonapi_resource_type = old_type
end
def test_config_plural
with_jsonapi_resource_type :plural do
hash = serializable(@comment, adapter: :json_api).serializable_hash
assert_equal('comments', hash[:data][:type])
end
def test_config_plural
with_jsonapi_resource_type :plural do
hash = serializable(@comment, adapter: :json_api).serializable_hash
assert_equal('comments', hash[:data][:type])
end
end
def test_config_singular
with_jsonapi_resource_type :singular do
hash = serializable(@comment, adapter: :json_api).serializable_hash
assert_equal('comment', hash[:data][:type])
end
def test_config_singular
with_jsonapi_resource_type :singular do
hash = serializable(@comment, adapter: :json_api).serializable_hash
assert_equal('comment', hash[:data][:type])
end
end
def test_explicit_type_value
hash = serializable(@author, serializer: ProfileTypeSerializer, adapter: :json_api).serializable_hash
assert_equal('profile', hash.fetch(:data).fetch(:type))
end
def test_explicit_type_value
hash = serializable(@author, serializer: ProfileTypeSerializer, adapter: :json_api).serializable_hash
assert_equal('profile', hash.fetch(:data).fetch(:type))
end
private
private
def serializable(resource, options = {})
ActiveModel::SerializableResource.new(resource, options)
end
def serializable(resource, options = {})
ActiveModel::SerializableResource.new(resource, options)
end
end
end

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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