mirror of
https://github.com/ditkrg/active_model_serializers.git
synced 2026-01-22 22:06:50 +00:00
Merge branch 'master' into domitian-move-namespace-of-adapter-to-active-model-serializers
Conflicts: CHANGELOG.md lib/active_model/serializer/adapter/attributes.rb lib/active_model/serializer/adapter/cached_serializer.rb lib/active_model/serializer/adapter/fragment_cache.rb lib/active_model/serializer/adapter/json_api.rb lib/active_model/serializer/adapter/json_api/link.rb test/adapter/fragment_cache_test.rb test/adapter/json_api/links_test.rb test/adapter/json_api/resource_type_config_test.rb
This commit is contained in:
commit
25c9df0b97
1
.gitignore
vendored
1
.gitignore
vendored
@ -22,3 +22,4 @@ tmp
|
|||||||
.ruby-version
|
.ruby-version
|
||||||
.ruby-gemset
|
.ruby-gemset
|
||||||
vendor/bundle
|
vendor/bundle
|
||||||
|
tags
|
||||||
|
|||||||
@ -19,7 +19,6 @@ ENV['FULL_BUILD'] ||= ENV['CI']
|
|||||||
# rubocop:enable Style/DoubleNegation
|
# rubocop:enable Style/DoubleNegation
|
||||||
|
|
||||||
## CONFIGURE SIMPLECOV
|
## CONFIGURE SIMPLECOV
|
||||||
SimpleCov.pid = $$ # In case there's any forking
|
|
||||||
|
|
||||||
SimpleCov.profiles.define 'app' do
|
SimpleCov.profiles.define 'app' do
|
||||||
coverage_dir 'coverage'
|
coverage_dir 'coverage'
|
||||||
|
|||||||
23
CHANGELOG.md
23
CHANGELOG.md
@ -1,9 +1,30 @@
|
|||||||
## 0.10.x
|
## 0.10.x
|
||||||
|
|
||||||
Breaking changes:
|
Breaking changes:
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
- [#1515](https://github.com/rails-api/active_model_serializers/pull/1515) Adds support for symbols to the
|
||||||
|
`ActiveModel::Serializer.type` method. (@groyoh)
|
||||||
|
- [#1504](https://github.com/rails-api/active_model_serializers/pull/1504) Adds the changes missing from #1454
|
||||||
|
and add more tests for resource identifier and relationship objects. Fix association block with link
|
||||||
|
returning `data: nil`.(@groyoh)
|
||||||
|
- [#1372](https://github.com/rails-api/active_model_serializers/pull/1372) Support
|
||||||
|
cache_store.read_multi. (@LcpMarvel)
|
||||||
|
- [#1018](https://github.com/rails-api/active_model_serializers/pull/1018) Add more tests and docs for top-level links. (@leandrocp)
|
||||||
|
- [#1454](https://github.com/rails-api/active_model_serializers/pull/1454) Add support for
|
||||||
|
relationship-level links and meta attributes. (@beauby)
|
||||||
|
- [#1340](https://github.com/rails-api/active_model_serializers/pull/1340) Add support for resource-level meta. (@beauby)
|
||||||
|
|
||||||
Fixes:
|
Fixes:
|
||||||
|
- [#1516](https://github.com/rails-api/active_model_serializers/pull/1501) No longer return a nil href when only
|
||||||
|
adding meta to a relationship link. (@groyoh)
|
||||||
|
- [#1458](https://github.com/rails-api/active_model_serializers/pull/1458) Preserve the serializer
|
||||||
|
type when fragment caching. (@bdmac)
|
||||||
|
- [#1477](https://github.com/rails-api/active_model_serializers/pull/1477) Fix `fragment_cached?`
|
||||||
|
method to check if caching. (@bdmac)
|
||||||
|
- [#1501](https://github.com/rails-api/active_model_serializers/pull/1501) Adds tests for SerializableResource::use_adapter?,doc typos (@domitian)
|
||||||
- [#1488](https://github.com/rails-api/active_model_serializers/pull/1488) Require ActiveSupport's string inflections (@nate00)
|
- [#1488](https://github.com/rails-api/active_model_serializers/pull/1488) Require ActiveSupport's string inflections (@nate00)
|
||||||
|
|
||||||
Misc:
|
Misc:
|
||||||
|
|
||||||
### v0.10.0.rc4 (2016/01/27 11:00 +00:00)
|
### v0.10.0.rc4 (2016/01/27 11:00 +00:00)
|
||||||
@ -415,7 +436,7 @@ Features:
|
|||||||
'[Revert the serializers API as other alternatives are now also under discussion](https://github.com/rails/rails/commit/0a4035b12a6c59253cb60f9e3456513c6a6a9d33)'.
|
'[Revert the serializers API as other alternatives are now also under discussion](https://github.com/rails/rails/commit/0a4035b12a6c59253cb60f9e3456513c6a6a9d33)'.
|
||||||
- [Proposed Implementation to Rails 3.2 by @wycats and @josevalim (November 25, 2011)](https://github.com/rails/rails/pull/3753)
|
- [Proposed Implementation to Rails 3.2 by @wycats and @josevalim (November 25, 2011)](https://github.com/rails/rails/pull/3753)
|
||||||
- [Creation of `ActionController::Serialization`, initial serializer
|
- [Creation of `ActionController::Serialization`, initial serializer
|
||||||
support (September, 26 2011)](https://github.com/rails/rails/commit/8ff7693a8dc61f43fc4eaf72ed24d3b8699191fe0).
|
support (September, 26 2011)](https://github.com/rails/rails/commit/8ff7693a8dc61f43fc4eaf72ed24d3b8699191fe).
|
||||||
- [Docs and CHANGELOG](https://github.com/rails/rails/commit/696d01f7f4a8ed787924a41cce6df836cd73c46f)
|
- [Docs and CHANGELOG](https://github.com/rails/rails/commit/696d01f7f4a8ed787924a41cce6df836cd73c46f)
|
||||||
- [Deprecation of ActiveModel::Serialization to ActiveModel::Serializable](https://github.com/rails/rails/blob/696d01f7f4a8ed787924a41cce6df836cd73c46f/activemodel/lib/active_model/serialization.rb)
|
- [Deprecation of ActiveModel::Serialization to ActiveModel::Serializable](https://github.com/rails/rails/blob/696d01f7f4a8ed787924a41cce6df836cd73c46f/activemodel/lib/active_model/serialization.rb)
|
||||||
- [Creation of `ActiveModel::Serialization` from `ActiveModel::Serializer` in Rails (2009)](https://github.com/rails/rails/commit/c6bc8e662614be711f45a8d4b231d5f993b024a7#diff-d029b9768d8df0407a35804a468e3ae5)
|
- [Creation of `ActiveModel::Serialization` from `ActiveModel::Serializer` in Rails (2009)](https://github.com/rails/rails/commit/c6bc8e662614be711f45a8d4b231d5f993b024a7#diff-d029b9768d8df0407a35804a468e3ae5)
|
||||||
|
|||||||
1
Gemfile
1
Gemfile
@ -41,7 +41,6 @@ group :test do
|
|||||||
gem 'activerecord-jdbcsqlite3-adapter', platform: :jruby
|
gem 'activerecord-jdbcsqlite3-adapter', platform: :jruby
|
||||||
|
|
||||||
gem 'codeclimate-test-reporter', require: false
|
gem 'codeclimate-test-reporter', require: false
|
||||||
gem 'simplecov', '~> 0.10', require: false, group: :development
|
|
||||||
end
|
end
|
||||||
|
|
||||||
group :development, :test do
|
group :development, :test do
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
(Windows: [](https://ci.appveyor.com/project/joaomdmoura/active-model-serializers/branch/master))
|
(Windows: [](https://ci.appveyor.com/project/joaomdmoura/active-model-serializers/branch/master))
|
||||||
[](https://codeclimate.com/github/rails-api/active_model_serializers)
|
[](https://codeclimate.com/github/rails-api/active_model_serializers)
|
||||||
[](https://codeclimate.com/github/rails-api/active_model_serializers/coverage)
|
[](https://codeclimate.com/github/rails-api/active_model_serializers/coverage)
|
||||||
|
[](http://issuestats.com/github/rails-api/active_model_serializers) [](http://issuestats.com/github/rails-api/active_model_serializers)
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
|
|||||||
2
Rakefile
2
Rakefile
@ -29,7 +29,7 @@ else
|
|||||||
Rake::Task[:rubocop].clear if Rake::Task.task_defined?(:rubocop)
|
Rake::Task[:rubocop].clear if Rake::Task.task_defined?(:rubocop)
|
||||||
desc 'Execute rubocop'
|
desc 'Execute rubocop'
|
||||||
RuboCop::RakeTask.new(:rubocop) do |task|
|
RuboCop::RakeTask.new(:rubocop) do |task|
|
||||||
task.options = ['--rails', '--display-cop-names', '--display-style-guide']
|
task.options = ['--display-cop-names', '--display-style-guide']
|
||||||
task.fail_on_error = true
|
task.fail_on_error = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -51,6 +51,7 @@ Gem::Specification.new do |spec|
|
|||||||
spec.add_development_dependency 'will_paginate', '~> 3.0', '>= 3.0.7'
|
spec.add_development_dependency 'will_paginate', '~> 3.0', '>= 3.0.7'
|
||||||
|
|
||||||
spec.add_development_dependency 'bundler', '~> 1.6'
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
||||||
|
spec.add_development_dependency 'simplecov', '~> 0.11'
|
||||||
spec.add_development_dependency 'timecop', '~> 0.7'
|
spec.add_development_dependency 'timecop', '~> 0.7'
|
||||||
spec.add_development_dependency 'minitest-reporters'
|
spec.add_development_dependency 'minitest-reporters'
|
||||||
spec.add_development_dependency 'grape', ['>= 0.13', '< 1.0']
|
spec.add_development_dependency 'grape', ['>= 0.13', '< 1.0']
|
||||||
|
|||||||
@ -56,7 +56,7 @@ High-level overview:
|
|||||||
- `:each_serializer` specifies the serializer for each resource in the collection.
|
- `:each_serializer` specifies the serializer for each resource in the collection.
|
||||||
- For a single resource, the `:serializer` option is the resource serializer.
|
- For a single resource, the `:serializer` option is the resource serializer.
|
||||||
- Options are partitioned in serializer options and adapter options. Keys for adapter options are specified by
|
- Options are partitioned in serializer options and adapter options. Keys for adapter options are specified by
|
||||||
[`ADAPTER_OPTIONS`](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model/serializable_resource.rb#L4).
|
[`ADAPTER_OPTION_KEYS`](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model/serializable_resource.rb#L4).
|
||||||
The remaining options are serializer options.
|
The remaining options are serializer options.
|
||||||
|
|
||||||
Details:
|
Details:
|
||||||
@ -64,7 +64,7 @@ Details:
|
|||||||
1. **ActionController::Serialization**
|
1. **ActionController::Serialization**
|
||||||
1. `serializable_resource = ActiveModel::SerializableResource.new(resource, options)`
|
1. `serializable_resource = ActiveModel::SerializableResource.new(resource, options)`
|
||||||
1. `options` are partitioned into `adapter_opts` and everything else (`serializer_opts`).
|
1. `options` are partitioned into `adapter_opts` and everything else (`serializer_opts`).
|
||||||
The adapter options keys for the are defined by `ADAPTER_OPTIONS`.
|
The `adapter_opts` keys are defined in `ActiveModel::SerializableResource::ADAPTER_OPTION_KEYS`.
|
||||||
1. **ActiveModel::SerializableResource**
|
1. **ActiveModel::SerializableResource**
|
||||||
1. `if serializable_resource.serializer?` (there is a serializer for the resource, and an adapter is used.)
|
1. `if serializable_resource.serializer?` (there is a serializer for the resource, and an adapter is used.)
|
||||||
- Where `serializer?` is `use_adapter? && !!(serializer)`
|
- Where `serializer?` is `use_adapter? && !!(serializer)`
|
||||||
|
|||||||
@ -103,7 +103,46 @@ PR please :)
|
|||||||
|
|
||||||
#### links
|
#### links
|
||||||
|
|
||||||
PR please :)
|
##### How to add top-level links
|
||||||
|
|
||||||
|
JsonApi supports a [links object](http://jsonapi.org/format/#document-links) to be specified at top-level, that you can specify in the `render`:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
links_object = {
|
||||||
|
href: "http://example.com/api/posts",
|
||||||
|
meta: {
|
||||||
|
count: 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render json: @posts, links: links_object
|
||||||
|
```
|
||||||
|
|
||||||
|
That's the result:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"type": "posts",
|
||||||
|
"id": "1",
|
||||||
|
"attributes": {
|
||||||
|
"title": "JSON API is awesome!",
|
||||||
|
"body": "You should be using JSON API",
|
||||||
|
"created": "2015-05-22T14:56:29.000Z",
|
||||||
|
"updated": "2015-05-22T14:56:28.000Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"links": {
|
||||||
|
"href": "http://example.com/api/posts",
|
||||||
|
"meta": {
|
||||||
|
"count": 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This feature is specific to JsonApi, so you have to use the use the [JsonApi Adapter](adapters.md#jsonapi)
|
||||||
|
|
||||||
### serializer_opts
|
### serializer_opts
|
||||||
|
|
||||||
|
|||||||
@ -107,12 +107,30 @@ end
|
|||||||
|
|
||||||
#### ::type
|
#### ::type
|
||||||
|
|
||||||
e.g.
|
The `::type` method defines the JSONAPI [type](http://jsonapi.org/format/#document-resource-object-identification) that will be rendered for this serializer.
|
||||||
|
It either takes a `String` or `Symbol` as parameter.
|
||||||
|
|
||||||
|
Note: This method is useful only when using the `:json_api` adapter.
|
||||||
|
|
||||||
|
Examples:
|
||||||
```ruby
|
```ruby
|
||||||
class UserProfileSerializer < ActiveModel::Serializer
|
class UserProfileSerializer < ActiveModel::Serializer
|
||||||
type 'profile'
|
type 'profile'
|
||||||
end
|
end
|
||||||
|
class AuthorProfileSerializer < ActiveModel::Serializer
|
||||||
|
type :profile
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
With the `:json_api` adapter, the previous serializers would be rendered as:
|
||||||
|
|
||||||
|
``` json
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"id": "1",
|
||||||
|
"type": "profile"
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### ::link
|
#### ::link
|
||||||
|
|||||||
@ -74,32 +74,30 @@ ActiveModelSerializers pagination relies on a paginated collection with the meth
|
|||||||
|
|
||||||
If you are using `JSON` adapter, pagination links will not be included automatically, but it is possible to do so using `meta` key.
|
If you are using `JSON` adapter, pagination links will not be included automatically, but it is possible to do so using `meta` key.
|
||||||
|
|
||||||
In your action specify a custom serializer.
|
Add this method to your base API controller.
|
||||||
```ruby
|
|
||||||
render json: @posts, serializer: PaginatedSerializer, each_serializer: PostPreviewSerializer
|
|
||||||
```
|
|
||||||
|
|
||||||
And then, you could do something like the following class.
|
|
||||||
```ruby
|
```ruby
|
||||||
class PaginatedSerializer < ActiveModel::Serializer::CollectionSerializer
|
def pagination_dict(object)
|
||||||
def initialize(object, options={})
|
{
|
||||||
meta_key = options[:meta_key] || :meta
|
current_page: object.current_page,
|
||||||
options[meta_key] ||= {}
|
next_page: object.next_page,
|
||||||
options[meta_key] = {
|
prev_page: object.prev_page,
|
||||||
current_page: object.current_page,
|
total_pages: object.total_pages,
|
||||||
next_page: object.next_page,
|
total_count: object.total_count
|
||||||
prev_page: object.prev_page,
|
}
|
||||||
total_pages: object.total_pages,
|
|
||||||
total_count: object.total_count
|
|
||||||
}
|
|
||||||
super(object, options)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Then, use it on your render method.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
render json: posts, meta: pagination_dict(posts)
|
||||||
|
```
|
||||||
|
|
||||||
ex.
|
ex.
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"articles": [
|
"posts": [
|
||||||
{
|
{
|
||||||
"id": 2,
|
"id": 2,
|
||||||
"title": "JSON API paints my bikeshed!",
|
"title": "JSON API paints my bikeshed!",
|
||||||
|
|||||||
@ -9,6 +9,7 @@ require 'active_model/serializer/configuration'
|
|||||||
require 'active_model/serializer/fieldset'
|
require 'active_model/serializer/fieldset'
|
||||||
require 'active_model/serializer/lint'
|
require 'active_model/serializer/lint'
|
||||||
require 'active_model/serializer/links'
|
require 'active_model/serializer/links'
|
||||||
|
require 'active_model/serializer/meta'
|
||||||
require 'active_model/serializer/type'
|
require 'active_model/serializer/type'
|
||||||
|
|
||||||
# ActiveModel::Serializer is an abstract class that is
|
# ActiveModel::Serializer is an abstract class that is
|
||||||
@ -20,6 +21,7 @@ module ActiveModel
|
|||||||
include Attributes
|
include Attributes
|
||||||
include Caching
|
include Caching
|
||||||
include Links
|
include Links
|
||||||
|
include Meta
|
||||||
include Type
|
include Type
|
||||||
# Deprecated
|
# Deprecated
|
||||||
require 'active_model_serializers/adapter'
|
require 'active_model_serializers/adapter'
|
||||||
@ -70,7 +72,7 @@ module ActiveModel
|
|||||||
|
|
||||||
# @api private
|
# @api private
|
||||||
# Find a serializer from a class and caches the lookup.
|
# Find a serializer from a class and caches the lookup.
|
||||||
# Preferentially retuns:
|
# Preferentially returns:
|
||||||
# 1. class name appended with "Serializer"
|
# 1. class name appended with "Serializer"
|
||||||
# 2. try again with superclass, if present
|
# 2. try again with superclass, if present
|
||||||
# 3. nil
|
# 3. nil
|
||||||
|
|||||||
13
lib/active_model/serializer/adapter/json_api/api_objects.rb
Normal file
13
lib/active_model/serializer/adapter/json_api/api_objects.rb
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
module Adapter
|
||||||
|
class JsonApi
|
||||||
|
module ApiObjects
|
||||||
|
extend ActiveSupport::Autoload
|
||||||
|
autoload :Relationship
|
||||||
|
autoload :ResourceIdentifier
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
module Adapter
|
||||||
|
class JsonApi
|
||||||
|
module ApiObjects
|
||||||
|
class Relationship
|
||||||
|
def initialize(parent_serializer, serializer, options = {}, links = {}, meta = nil)
|
||||||
|
@object = parent_serializer.object
|
||||||
|
@scope = parent_serializer.scope
|
||||||
|
|
||||||
|
@options = options
|
||||||
|
@data = data_for(serializer, options)
|
||||||
|
@links = links.each_with_object({}) do |(key, value), hash|
|
||||||
|
hash[key] = ActiveModelSerializers::Adapter::JsonApi::Link.new(parent_serializer, value).as_json
|
||||||
|
end
|
||||||
|
@meta = meta.respond_to?(:call) ? parent_serializer.instance_eval(&meta) : meta
|
||||||
|
end
|
||||||
|
|
||||||
|
def as_json
|
||||||
|
hash = {}
|
||||||
|
hash[:data] = data if options[:include_data]
|
||||||
|
links = self.links
|
||||||
|
hash[:links] = links if links.any?
|
||||||
|
meta = self.meta
|
||||||
|
hash[:meta] = meta if meta
|
||||||
|
|
||||||
|
hash
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
attr_reader :object, :scope, :data, :options, :links, :meta
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def data_for(serializer, options)
|
||||||
|
if serializer.respond_to?(:each)
|
||||||
|
serializer.map { |s| ResourceIdentifier.new(s).as_json }
|
||||||
|
else
|
||||||
|
if options[:virtual_value]
|
||||||
|
options[:virtual_value]
|
||||||
|
elsif serializer && serializer.object
|
||||||
|
ResourceIdentifier.new(serializer).as_json
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
module Adapter
|
||||||
|
class JsonApi
|
||||||
|
module ApiObjects
|
||||||
|
class ResourceIdentifier
|
||||||
|
def initialize(serializer)
|
||||||
|
@id = id_for(serializer)
|
||||||
|
@type = type_for(serializer)
|
||||||
|
end
|
||||||
|
|
||||||
|
def as_json
|
||||||
|
{ id: id, type: type }
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
attr_reader :id, :type
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def 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 id_for(serializer)
|
||||||
|
serializer.read_attribute_for_serialization(:id).to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
29
lib/active_model/serializer/adapter/json_api/meta.rb
Normal file
29
lib/active_model/serializer/adapter/json_api/meta.rb
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
module Adapter
|
||||||
|
class JsonApi
|
||||||
|
class Meta
|
||||||
|
def initialize(serializer)
|
||||||
|
@object = serializer.object
|
||||||
|
@scope = serializer.scope
|
||||||
|
|
||||||
|
# Use the return value of the block unless it is nil.
|
||||||
|
if serializer._meta.respond_to?(:call)
|
||||||
|
@value = instance_eval(&serializer._meta)
|
||||||
|
else
|
||||||
|
@value = serializer._meta
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def as_json
|
||||||
|
@value
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
attr_reader :object, :scope
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -9,7 +9,7 @@ module ActiveModel
|
|||||||
# @example
|
# @example
|
||||||
# Association.new(:comments, CommentSummarySerializer)
|
# Association.new(:comments, CommentSummarySerializer)
|
||||||
#
|
#
|
||||||
Association = Struct.new(:name, :serializer, :options) do
|
Association = Struct.new(:name, :serializer, :options, :links, :meta) do
|
||||||
# @return [Symbol]
|
# @return [Symbol]
|
||||||
#
|
#
|
||||||
def key
|
def key
|
||||||
|
|||||||
29
lib/active_model/serializer/meta.rb
Normal file
29
lib/active_model/serializer/meta.rb
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
module Meta
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
with_options instance_writer: false, instance_reader: true do |serializer|
|
||||||
|
serializer.class_attribute :_meta # @api private
|
||||||
|
end
|
||||||
|
|
||||||
|
extend ActiveSupport::Autoload
|
||||||
|
end
|
||||||
|
|
||||||
|
module ClassMethods
|
||||||
|
# Set the JSON API meta attribute of a serializer.
|
||||||
|
# @example
|
||||||
|
# class AdminAuthorSerializer < ActiveModel::Serializer
|
||||||
|
# meta { stuff: 'value' }
|
||||||
|
# @example
|
||||||
|
# meta do
|
||||||
|
# { comment_count: object.comments.count }
|
||||||
|
# end
|
||||||
|
def meta(value = nil, &block)
|
||||||
|
self._meta = block || value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -34,6 +34,43 @@ module ActiveModel
|
|||||||
# So you can inspect reflections in your Adapters.
|
# So you can inspect reflections in your Adapters.
|
||||||
#
|
#
|
||||||
class Reflection < Field
|
class Reflection < Field
|
||||||
|
def initialize(*)
|
||||||
|
super
|
||||||
|
@_links = {}
|
||||||
|
@_include_data = true
|
||||||
|
end
|
||||||
|
|
||||||
|
def link(name, value = nil, &block)
|
||||||
|
@_links[name] = block || value
|
||||||
|
:nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def meta(value = nil, &block)
|
||||||
|
@_meta = block || value
|
||||||
|
:nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def include_data(value = true)
|
||||||
|
@_include_data = value
|
||||||
|
:nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def value(serializer)
|
||||||
|
@object = serializer.object
|
||||||
|
@scope = serializer.scope
|
||||||
|
|
||||||
|
if block
|
||||||
|
block_value = instance_eval(&block)
|
||||||
|
if block_value == :nil
|
||||||
|
serializer.read_attribute_for_serialization(name)
|
||||||
|
else
|
||||||
|
block_value
|
||||||
|
end
|
||||||
|
else
|
||||||
|
serializer.read_attribute_for_serialization(name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Build association. This method is used internally to
|
# Build association. This method is used internally to
|
||||||
# build serializer's association by its reflection.
|
# build serializer's association by its reflection.
|
||||||
#
|
#
|
||||||
@ -59,6 +96,7 @@ module ActiveModel
|
|||||||
association_value = value(subject)
|
association_value = value(subject)
|
||||||
reflection_options = options.dup
|
reflection_options = options.dup
|
||||||
serializer_class = subject.class.serializer_for(association_value, reflection_options)
|
serializer_class = subject.class.serializer_for(association_value, reflection_options)
|
||||||
|
reflection_options[:include_data] = @_include_data
|
||||||
|
|
||||||
if serializer_class
|
if serializer_class
|
||||||
begin
|
begin
|
||||||
@ -73,9 +111,13 @@ module ActiveModel
|
|||||||
reflection_options[:virtual_value] = association_value
|
reflection_options[:virtual_value] = association_value
|
||||||
end
|
end
|
||||||
|
|
||||||
Association.new(name, serializer, reflection_options)
|
Association.new(name, serializer, reflection_options, @_links, @_meta)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
attr_accessor :object, :scope
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def serializer_options(subject, parent_serializer_options, reflection_options)
|
def serializer_options(subject, parent_serializer_options, reflection_options)
|
||||||
|
|||||||
@ -17,7 +17,7 @@ module ActiveModel
|
|||||||
# class AdminAuthorSerializer < ActiveModel::Serializer
|
# class AdminAuthorSerializer < ActiveModel::Serializer
|
||||||
# type 'authors'
|
# type 'authors'
|
||||||
def type(type)
|
def type(type)
|
||||||
self._type = type
|
self._type = type && type.to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -4,6 +4,7 @@ module ActiveModelSerializers
|
|||||||
def initialize(serializer, options = {})
|
def initialize(serializer, options = {})
|
||||||
super
|
super
|
||||||
@include_tree = ActiveModel::Serializer::IncludeTree.from_include_args(options[:include] || '*')
|
@include_tree = ActiveModel::Serializer::IncludeTree.from_include_args(options[:include] || '*')
|
||||||
|
@cached_attributes = options[:cache_attributes] || {}
|
||||||
end
|
end
|
||||||
|
|
||||||
def serializable_hash(options = nil)
|
def serializable_hash(options = nil)
|
||||||
@ -23,9 +24,38 @@ module ActiveModelSerializers
|
|||||||
private
|
private
|
||||||
|
|
||||||
def serializable_hash_for_collection(options)
|
def serializable_hash_for_collection(options)
|
||||||
|
cache_attributes
|
||||||
|
|
||||||
serializer.map { |s| Attributes.new(s, instance_options).serializable_hash(options) }
|
serializer.map { |s| Attributes.new(s, instance_options).serializable_hash(options) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Read cache from cache_store
|
||||||
|
# @return [Hash]
|
||||||
|
def cache_read_multi
|
||||||
|
return {} if ActiveModelSerializers.config.cache_store.blank?
|
||||||
|
|
||||||
|
keys = CachedSerializer.object_cache_keys(serializer, @include_tree)
|
||||||
|
|
||||||
|
return {} if keys.blank?
|
||||||
|
|
||||||
|
ActiveModelSerializers.config.cache_store.read_multi(*keys)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Set @cached_attributes
|
||||||
|
def cache_attributes
|
||||||
|
return if @cached_attributes.present?
|
||||||
|
|
||||||
|
@cached_attributes = cache_read_multi
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get attributes from @cached_attributes
|
||||||
|
# @return [Hash] cached attributes
|
||||||
|
def cached_attributes(cached_serializer)
|
||||||
|
return yield unless cached_serializer.cached?
|
||||||
|
|
||||||
|
@cached_attributes.fetch(cached_serializer.cache_key) { yield }
|
||||||
|
end
|
||||||
|
|
||||||
def serializable_hash_for_single_resource(options)
|
def serializable_hash_for_single_resource(options)
|
||||||
resource = resource_object_for(options)
|
resource = resource_object_for(options)
|
||||||
relationships = resource_relationships(options)
|
relationships = resource_relationships(options)
|
||||||
@ -55,8 +85,12 @@ module ActiveModelSerializers
|
|||||||
end
|
end
|
||||||
|
|
||||||
def resource_object_for(options)
|
def resource_object_for(options)
|
||||||
cache_check(serializer) do
|
cached_serializer = CachedSerializer.new(serializer)
|
||||||
serializer.attributes(options[:fields])
|
|
||||||
|
cached_attributes(cached_serializer) do
|
||||||
|
cached_serializer.cache_check(self) do
|
||||||
|
serializer.attributes(options[:fields])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -23,14 +23,16 @@ module ActiveModelSerializers
|
|||||||
end
|
end
|
||||||
|
|
||||||
def fragment_cached?
|
def fragment_cached?
|
||||||
@klass._cache_only && !@klass._cache_except || !@klass._cache_only && @klass._cache_except
|
@klass._cache && (@klass._cache_only && !@klass._cache_except || !@klass._cache_only && @klass._cache_except)
|
||||||
end
|
end
|
||||||
|
|
||||||
def cache_key
|
def cache_key
|
||||||
|
return @cache_key if defined?(@cache_key)
|
||||||
|
|
||||||
parts = []
|
parts = []
|
||||||
parts << object_cache_key
|
parts << object_cache_key
|
||||||
parts << @klass._cache_digest unless @klass._cache_options && @klass._cache_options[:skip_digest]
|
parts << @klass._cache_digest unless @klass._cache_options && @klass._cache_options[:skip_digest]
|
||||||
parts.join('/')
|
@cache_key = parts.join('/')
|
||||||
end
|
end
|
||||||
|
|
||||||
def object_cache_key
|
def object_cache_key
|
||||||
@ -38,6 +40,38 @@ module ActiveModelSerializers
|
|||||||
object_time_safe = object_time_safe.strftime('%Y%m%d%H%M%S%9N') if object_time_safe.respond_to?(:strftime)
|
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
|
(@klass._cache_key) ? "#{@klass._cache_key}/#{@cached_serializer.object.id}-#{object_time_safe}" : @cached_serializer.object.cache_key
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# find all cache_key for the collection_serializer
|
||||||
|
# @param collection_serializer
|
||||||
|
# @param include_tree
|
||||||
|
# @return [Array] all cache_key of collection_serializer
|
||||||
|
def self.object_cache_keys(serializers, include_tree)
|
||||||
|
cache_keys = []
|
||||||
|
|
||||||
|
serializers.each do |serializer|
|
||||||
|
cache_keys << object_cache_key(serializer)
|
||||||
|
|
||||||
|
serializer.associations(include_tree).each do |association|
|
||||||
|
if association.serializer.respond_to?(:each)
|
||||||
|
association.serializer.each do |sub_serializer|
|
||||||
|
cache_keys << object_cache_key(sub_serializer)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
cache_keys << object_cache_key(association.serializer)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
cache_keys.compact.uniq
|
||||||
|
end
|
||||||
|
|
||||||
|
# @return [String, nil] the cache_key of the serializer or nil
|
||||||
|
def self.object_cache_key(serializer)
|
||||||
|
return unless serializer.present? && serializer.object.present?
|
||||||
|
|
||||||
|
cached_serializer = new(serializer)
|
||||||
|
cached_serializer.cached? ? cached_serializer.cache_key : nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -93,6 +93,10 @@ module ActiveModelSerializers
|
|||||||
|
|
||||||
cached.constantize.cache(klass._cache_options)
|
cached.constantize.cache(klass._cache_options)
|
||||||
|
|
||||||
|
# Preserve the type setting in the cached/non-cached serializer classes
|
||||||
|
cached.constantize.type(klass._type)
|
||||||
|
non_cached.constantize.type(klass._type)
|
||||||
|
|
||||||
cached.constantize.fragmented(serializer)
|
cached.constantize.fragmented(serializer)
|
||||||
non_cached.constantize.fragmented(serializer)
|
non_cached.constantize.fragmented(serializer)
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,9 @@ module ActiveModelSerializers
|
|||||||
autoload :PaginationLinks
|
autoload :PaginationLinks
|
||||||
autoload :FragmentCache
|
autoload :FragmentCache
|
||||||
autoload :Link
|
autoload :Link
|
||||||
|
require 'active_model/serializer/adapter/json_api/meta'
|
||||||
autoload :Deserialization
|
autoload :Deserialization
|
||||||
|
require 'active_model/serializer/adapter/json_api/api_objects'
|
||||||
|
|
||||||
# TODO: if we like this abstraction and other API objects to it,
|
# TODO: if we like this abstraction and other API objects to it,
|
||||||
# then extract to its own file and require it.
|
# then extract to its own file and require it.
|
||||||
@ -96,7 +98,7 @@ module ActiveModelSerializers
|
|||||||
end
|
end
|
||||||
|
|
||||||
def process_resource(serializer, primary)
|
def process_resource(serializer, primary)
|
||||||
resource_identifier = resource_identifier_for(serializer)
|
resource_identifier = ActiveModel::Serializer::Adapter::JsonApi::ApiObjects::ResourceIdentifier.new(serializer).as_json
|
||||||
return false unless @resource_identifiers.add?(resource_identifier)
|
return false unless @resource_identifiers.add?(resource_identifier)
|
||||||
|
|
||||||
resource_object = resource_object_for(serializer)
|
resource_object = resource_object_for(serializer)
|
||||||
@ -126,37 +128,13 @@ module ActiveModelSerializers
|
|||||||
process_relationships(serializer, include_tree)
|
process_relationships(serializer, include_tree)
|
||||||
end
|
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)
|
def attributes_for(serializer, fields)
|
||||||
serializer.attributes(fields).except(:id)
|
serializer.attributes(fields).except(:id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def resource_object_for(serializer)
|
def resource_object_for(serializer)
|
||||||
resource_object = cache_check(serializer) do
|
resource_object = cache_check(serializer) do
|
||||||
resource_object = resource_identifier_for(serializer)
|
resource_object = ActiveModel::Serializer::Adapter::JsonApi::ApiObjects::ResourceIdentifier.new(serializer).as_json
|
||||||
|
|
||||||
requested_fields = fieldset && fieldset.fields_for(resource_object[:type])
|
requested_fields = fieldset && fieldset.fields_for(resource_object[:type])
|
||||||
attributes = attributes_for(serializer, requested_fields)
|
attributes = attributes_for(serializer, requested_fields)
|
||||||
@ -164,33 +142,29 @@ module ActiveModelSerializers
|
|||||||
resource_object
|
resource_object
|
||||||
end
|
end
|
||||||
|
|
||||||
relationships = relationships_for(serializer)
|
requested_associations = fieldset.fields_for(resource_object[:type]) || '*'
|
||||||
|
relationships = relationships_for(serializer, requested_associations)
|
||||||
resource_object[:relationships] = relationships if relationships.any?
|
resource_object[:relationships] = relationships if relationships.any?
|
||||||
|
|
||||||
links = links_for(serializer)
|
links = links_for(serializer)
|
||||||
resource_object[:links] = links if links.any?
|
resource_object[:links] = links if links.any?
|
||||||
|
|
||||||
|
meta = meta_for(serializer)
|
||||||
|
resource_object[:meta] = meta unless meta.nil?
|
||||||
|
|
||||||
resource_object
|
resource_object
|
||||||
end
|
end
|
||||||
|
|
||||||
def relationship_value_for(serializer, options = {})
|
def relationships_for(serializer, requested_associations)
|
||||||
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)
|
include_tree = ActiveModel::Serializer::IncludeTree.from_include_args(requested_associations)
|
||||||
serializer.associations(include_tree).each_with_object({}) do |association, hash|
|
serializer.associations(include_tree).each_with_object({}) do |association, hash|
|
||||||
hash[association.key] = { data: relationship_value_for(association.serializer, association.options) }
|
hash[association.key] = ActiveModel::Serializer::Adapter::JsonApi::ApiObjects::Relationship.new(
|
||||||
|
serializer,
|
||||||
|
association.serializer,
|
||||||
|
association.options,
|
||||||
|
association.links,
|
||||||
|
association.meta
|
||||||
|
).as_json
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -203,6 +177,10 @@ module ActiveModelSerializers
|
|||||||
def pagination_links_for(serializer, options)
|
def pagination_links_for(serializer, options)
|
||||||
JsonApi::PaginationLinks.new(serializer.object, options[:serialization_context]).serializable_hash(options)
|
JsonApi::PaginationLinks.new(serializer.object, options[:serialization_context]).serializable_hash(options)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def meta_for(serializer)
|
||||||
|
ActiveModel::Serializer::Adapter::JsonApi::Meta.new(serializer).as_json
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -27,8 +27,9 @@ module ActiveModelSerializers
|
|||||||
def as_json
|
def as_json
|
||||||
return @value if @value
|
return @value if @value
|
||||||
|
|
||||||
hash = { href: @href }
|
hash = {}
|
||||||
hash.merge!(meta: @meta) if @meta
|
hash[:href] = @href if @href
|
||||||
|
hash[:meta] = @meta if @meta
|
||||||
|
|
||||||
hash
|
hash
|
||||||
end
|
end
|
||||||
|
|||||||
@ -45,6 +45,16 @@ module ActionController
|
|||||||
render json: @profiles, meta: { total: 10 }
|
render json: @profiles, meta: { total: 10 }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def render_array_using_implicit_serializer_and_links
|
||||||
|
with_adapter ActiveModelSerializers::Adapter::JsonApi do
|
||||||
|
@profiles = [
|
||||||
|
Profile.new(name: 'Name 1', description: 'Description 1', comments: 'Comments 1')
|
||||||
|
]
|
||||||
|
|
||||||
|
render json: @profiles, links: { self: 'http://example.com/api/profiles/1' }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def render_object_with_cache_enabled
|
def render_object_with_cache_enabled
|
||||||
@comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
@comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||||
@author = Author.new(id: 1, name: 'Joao Moura.')
|
@author = Author.new(id: 1, name: 'Joao Moura.')
|
||||||
@ -254,6 +264,29 @@ module ActionController
|
|||||||
assert_equal expected.to_json, @response.body
|
assert_equal expected.to_json, @response.body
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_render_array_using_implicit_serializer_and_links
|
||||||
|
get :render_array_using_implicit_serializer_and_links
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: assigns(:profiles).first.id.to_s,
|
||||||
|
type: 'profiles',
|
||||||
|
attributes: {
|
||||||
|
name: 'Name 1',
|
||||||
|
description: 'Description 1'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
links: {
|
||||||
|
self: 'http://example.com/api/profiles/1'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal 'application/json', @response.content_type
|
||||||
|
assert_equal expected.to_json, @response.body
|
||||||
|
end
|
||||||
|
|
||||||
def test_render_with_cache_enable
|
def test_render_with_cache_enable
|
||||||
expected = {
|
expected = {
|
||||||
id: 1,
|
id: 1,
|
||||||
|
|||||||
@ -2,6 +2,14 @@ require 'test_helper'
|
|||||||
module ActiveModelSerializers
|
module ActiveModelSerializers
|
||||||
module Adapter
|
module Adapter
|
||||||
class FragmentCacheTest < ActiveSupport::TestCase
|
class FragmentCacheTest < ActiveSupport::TestCase
|
||||||
|
TypedRoleSerializer = Class.new(ActiveModel::Serializer) do
|
||||||
|
type 'my-roles'
|
||||||
|
cache only: [:name], skip_digest: true
|
||||||
|
attributes :id, :name, :description
|
||||||
|
|
||||||
|
belongs_to :author
|
||||||
|
end
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
super
|
super
|
||||||
@spam = Spam::UnrelatedLink.new(id: 'spam-id-1')
|
@spam = Spam::UnrelatedLink.new(id: 'spam-id-1')
|
||||||
@ -30,7 +38,11 @@ module ActiveModelSerializers
|
|||||||
}
|
}
|
||||||
assert_equal(@spam_hash.fetch, expected_result)
|
assert_equal(@spam_hash.fetch, expected_result)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_fragment_fetch_with_type_override
|
||||||
|
serialization = serializable(Role.new(name: 'Another Author'), serializer: TypedRoleSerializer, adapter: :json_api).serializable_hash
|
||||||
|
assert_equal(TypedRoleSerializer._type, serialization.fetch(:data).fetch(:type))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
168
test/adapter/json_api/api_objects/relationship_test.rb
Normal file
168
test/adapter/json_api/api_objects/relationship_test.rb
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
module Adapter
|
||||||
|
class JsonApi
|
||||||
|
module ApiObjects
|
||||||
|
class RelationshipTest < ActiveSupport::TestCase
|
||||||
|
def setup
|
||||||
|
@blog = Blog.new(id: 1)
|
||||||
|
@author = Author.new(id: 1, name: 'Steve K.', blog: @blog)
|
||||||
|
@serializer = BlogSerializer.new(@blog)
|
||||||
|
ActionController::Base.cache_store.clear
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_with_data
|
||||||
|
expected = {
|
||||||
|
data: {
|
||||||
|
id: '1',
|
||||||
|
type: 'blogs'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test_relationship(expected, options: { include_data: true })
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_with_nil_model
|
||||||
|
@serializer = BlogSerializer.new(nil)
|
||||||
|
expected = { data: nil }
|
||||||
|
test_relationship(expected, options: { include_data: true })
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_with_nil_serializer
|
||||||
|
@serializer = nil
|
||||||
|
expected = { data: nil }
|
||||||
|
test_relationship(expected, options: { include_data: true })
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_with_data_array
|
||||||
|
posts = [Post.new(id: 1), Post.new(id: 2)]
|
||||||
|
@serializer = ActiveModel::Serializer::CollectionSerializer.new(posts)
|
||||||
|
@author.posts = posts
|
||||||
|
@author.blog = nil
|
||||||
|
expected = {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
type: 'posts'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
type: 'posts'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
test_relationship(expected, options: { include_data: true })
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_data_not_included
|
||||||
|
test_relationship({}, options: { include_data: false })
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_simple_link
|
||||||
|
links = { self: 'a link' }
|
||||||
|
test_relationship({ links: { self: 'a link' } }, links: links)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_many_links
|
||||||
|
links = {
|
||||||
|
self: 'a link',
|
||||||
|
related: 'another link'
|
||||||
|
}
|
||||||
|
expected = {
|
||||||
|
links: {
|
||||||
|
self: 'a link',
|
||||||
|
related: 'another link'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test_relationship(expected, links: links)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_block_link
|
||||||
|
links = { self: proc { "#{object.id}" } }
|
||||||
|
expected = { links: { self: "#{@blog.id}" } }
|
||||||
|
test_relationship(expected, links: links)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_block_link_with_meta
|
||||||
|
links = {
|
||||||
|
self: proc do
|
||||||
|
href "#{object.id}"
|
||||||
|
meta(id: object.id)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
expected = {
|
||||||
|
links: {
|
||||||
|
self: {
|
||||||
|
href: "#{@blog.id}",
|
||||||
|
meta: { id: @blog.id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test_relationship(expected, links: links)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_simple_meta
|
||||||
|
meta = { id: '1' }
|
||||||
|
expected = { meta: meta }
|
||||||
|
test_relationship(expected, meta: meta)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_block_meta
|
||||||
|
meta = proc do
|
||||||
|
{ id: object.id }
|
||||||
|
end
|
||||||
|
expected = {
|
||||||
|
meta: {
|
||||||
|
id: @blog.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test_relationship(expected, meta: meta)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_with_everything
|
||||||
|
links = {
|
||||||
|
self: 'a link',
|
||||||
|
related: proc do
|
||||||
|
href "#{object.id}"
|
||||||
|
meta object.id
|
||||||
|
end
|
||||||
|
|
||||||
|
}
|
||||||
|
meta = proc do
|
||||||
|
{ id: object.id }
|
||||||
|
end
|
||||||
|
expected = {
|
||||||
|
data: {
|
||||||
|
id: '1',
|
||||||
|
type: 'blogs'
|
||||||
|
},
|
||||||
|
links: {
|
||||||
|
self: 'a link',
|
||||||
|
related: {
|
||||||
|
href: '1', meta: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
meta: {
|
||||||
|
id: @blog.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test_relationship(expected, meta: meta, options: { include_data: true }, links: links)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def test_relationship(expected, params = {})
|
||||||
|
options = params.fetch(:options, {})
|
||||||
|
links = params.fetch(:links, {})
|
||||||
|
meta = params[:meta]
|
||||||
|
parent_serializer = AuthorSerializer.new(@author)
|
||||||
|
relationship = Relationship.new(parent_serializer, @serializer, options, links, meta)
|
||||||
|
assert_equal(expected, relationship.as_json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,88 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
module Adapter
|
||||||
|
class JsonApi
|
||||||
|
module ApiObjects
|
||||||
|
class ResourceIdentifierTest < ActiveSupport::TestCase
|
||||||
|
class WithDefinedTypeSerializer < Serializer
|
||||||
|
type 'with_defined_type'
|
||||||
|
end
|
||||||
|
|
||||||
|
class WithDefinedIdSerializer < Serializer
|
||||||
|
def id
|
||||||
|
'special_id'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class FragmentedSerializer < Serializer; end
|
||||||
|
|
||||||
|
def setup
|
||||||
|
@model = Author.new(id: 1, name: 'Steve K.')
|
||||||
|
ActionController::Base.cache_store.clear
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_defined_type
|
||||||
|
test_type(WithDefinedTypeSerializer, 'with_defined_type')
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_singular_type
|
||||||
|
test_type_inflection(AuthorSerializer, 'author', :singular)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_plural_type
|
||||||
|
test_type_inflection(AuthorSerializer, 'authors', :plural)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_id_defined_on_object
|
||||||
|
test_id(AuthorSerializer, @model.id.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_id_defined_on_serializer
|
||||||
|
test_id(WithDefinedIdSerializer, 'special_id')
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_id_defined_on_fragmented
|
||||||
|
FragmentedSerializer.fragmented(WithDefinedIdSerializer.new(@author))
|
||||||
|
test_id(FragmentedSerializer, 'special_id')
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def test_type_inflection(serializer_class, expected_type, inflection)
|
||||||
|
original_inflection = ActiveModelSerializers.config.jsonapi_resource_type
|
||||||
|
ActiveModelSerializers.config.jsonapi_resource_type = inflection
|
||||||
|
test_type(serializer_class, expected_type)
|
||||||
|
ActiveModelSerializers.config.jsonapi_resource_type = original_inflection
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_type(serializer_class, expected_type)
|
||||||
|
serializer = serializer_class.new(@model)
|
||||||
|
resource_identifier = ResourceIdentifier.new(serializer)
|
||||||
|
expected = {
|
||||||
|
id: @model.id.to_s,
|
||||||
|
type: expected_type
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal(expected, resource_identifier.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_id(serializer_class, id)
|
||||||
|
serializer = serializer_class.new(@model)
|
||||||
|
resource_identifier = ResourceIdentifier.new(serializer)
|
||||||
|
inflection = ActiveModelSerializers.config.jsonapi_resource_type
|
||||||
|
type = @model.class.model_name.send(inflection)
|
||||||
|
expected = {
|
||||||
|
id: id,
|
||||||
|
type: type
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal(expected, resource_identifier.as_json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -20,7 +20,7 @@ module ActiveModelSerializers
|
|||||||
|
|
||||||
def setup
|
def setup
|
||||||
@post = Post.new(id: 1337, comments: [], author: nil)
|
@post = Post.new(id: 1337, comments: [], author: nil)
|
||||||
@author = LinkAuthor.new(id: 1337)
|
@author = LinkAuthor.new(id: 1337, posts: [@post])
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_toplevel_links
|
def test_toplevel_links
|
||||||
@ -46,6 +46,24 @@ module ActiveModelSerializers
|
|||||||
assert_equal(expected, hash[:links])
|
assert_equal(expected, hash[:links])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_nil_toplevel_links
|
||||||
|
hash = ActiveModel::SerializableResource.new(
|
||||||
|
@post,
|
||||||
|
adapter: :json_api,
|
||||||
|
links: nil
|
||||||
|
).serializable_hash
|
||||||
|
refute hash.key?(:links), 'No links key to be output'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_nil_toplevel_links_json_adapter
|
||||||
|
hash = ActiveModel::SerializableResource.new(
|
||||||
|
@post,
|
||||||
|
adapter: :json,
|
||||||
|
links: nil
|
||||||
|
).serializable_hash
|
||||||
|
refute hash.key?(:links), 'No links key to be output'
|
||||||
|
end
|
||||||
|
|
||||||
def test_resource_links
|
def test_resource_links
|
||||||
hash = serializable(@author, adapter: :json_api).serializable_hash
|
hash = serializable(@author, adapter: :json_api).serializable_hash
|
||||||
expected = {
|
expected = {
|
||||||
|
|||||||
192
test/adapter/json_api/relationship_test.rb
Normal file
192
test/adapter/json_api/relationship_test.rb
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
module Adapter
|
||||||
|
class JsonApi
|
||||||
|
class RelationshipTest < ActiveSupport::TestCase
|
||||||
|
RelationshipAuthor = Class.new(::Model)
|
||||||
|
class RelationshipAuthorSerializer < ActiveModel::Serializer
|
||||||
|
has_one :bio do
|
||||||
|
link :self, '//example.com/link_author/relationships/bio'
|
||||||
|
end
|
||||||
|
|
||||||
|
has_one :profile do
|
||||||
|
link :related do
|
||||||
|
"//example.com/profiles/#{object.profile.id}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
has_many :locations do
|
||||||
|
link :related do
|
||||||
|
ids = object.locations.map(&:id).join(',')
|
||||||
|
href "//example.com/locations/#{ids}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
has_many :posts do
|
||||||
|
link :related do
|
||||||
|
ids = object.posts.map(&:id).join(',')
|
||||||
|
href "//example.com/posts/#{ids}"
|
||||||
|
meta ids: ids
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
has_many :comments do
|
||||||
|
link :self do
|
||||||
|
meta ids: [1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
has_many :roles do
|
||||||
|
meta count: object.posts.count
|
||||||
|
end
|
||||||
|
|
||||||
|
has_one :blog do
|
||||||
|
link :self, '//example.com/link_author/relationships/blog'
|
||||||
|
include_data false
|
||||||
|
end
|
||||||
|
|
||||||
|
belongs_to :reviewer do
|
||||||
|
meta name: 'Dan Brown'
|
||||||
|
include_data true
|
||||||
|
end
|
||||||
|
|
||||||
|
has_many :likes do
|
||||||
|
link :related do
|
||||||
|
ids = object.likes.map(&:id).join(',')
|
||||||
|
href "//example.com/likes/#{ids}"
|
||||||
|
meta ids: ids
|
||||||
|
end
|
||||||
|
meta liked: object.likes.any?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup
|
||||||
|
@post = Post.new(id: 1337, comments: [], author: nil)
|
||||||
|
@blog = Blog.new(id: 1337, name: 'extra')
|
||||||
|
@bio = Bio.new(id: 1337)
|
||||||
|
@like = Like.new(id: 1337)
|
||||||
|
@role = Role.new(id: 1337)
|
||||||
|
@profile = Profile.new(id: 1337)
|
||||||
|
@location = Location.new(id: 1337)
|
||||||
|
@reviewer = Author.new(id: 1337)
|
||||||
|
@comment = Comment.new(id: 1337)
|
||||||
|
@author = RelationshipAuthor.new(
|
||||||
|
id: 1337,
|
||||||
|
posts: [@post],
|
||||||
|
blog: @blog,
|
||||||
|
reviewer: @reviewer,
|
||||||
|
bio: @bio,
|
||||||
|
likes: [@like],
|
||||||
|
roles: [@role],
|
||||||
|
locations: [@location],
|
||||||
|
profile: @profile,
|
||||||
|
comments: [@comment]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_simple_link
|
||||||
|
expected = {
|
||||||
|
data: {
|
||||||
|
id: '1337',
|
||||||
|
type: 'bios'
|
||||||
|
},
|
||||||
|
links: {
|
||||||
|
self: '//example.com/link_author/relationships/bio'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_relationship(:bio, expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_block_link
|
||||||
|
expected = {
|
||||||
|
data: { id: '1337', type: 'profiles' },
|
||||||
|
links: { related: '//example.com/profiles/1337' }
|
||||||
|
}
|
||||||
|
assert_relationship(:profile, expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_block_link_href
|
||||||
|
expected = {
|
||||||
|
data: [{ id: '1337', type: 'locations' }],
|
||||||
|
links: {
|
||||||
|
related: { href: '//example.com/locations/1337' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_relationship(:locations, expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_block_link_href_and_meta
|
||||||
|
expected = {
|
||||||
|
data: [{ id: '1337', type: 'posts' }],
|
||||||
|
links: {
|
||||||
|
related: {
|
||||||
|
href: '//example.com/posts/1337',
|
||||||
|
meta: { ids: '1337' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_relationship(:posts, expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_block_link_meta
|
||||||
|
expected = {
|
||||||
|
data: [{ id: '1337', type: 'comments' }],
|
||||||
|
links: {
|
||||||
|
self: {
|
||||||
|
meta: { ids: [1] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_relationship(:comments, expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_meta
|
||||||
|
expected = {
|
||||||
|
data: [{ id: '1337', type: 'roles' }],
|
||||||
|
meta: { count: 1 }
|
||||||
|
}
|
||||||
|
assert_relationship(:roles, expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_not_including_data
|
||||||
|
expected = {
|
||||||
|
links: { self: '//example.com/link_author/relationships/blog' }
|
||||||
|
}
|
||||||
|
assert_relationship(:blog, expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_including_data_explicit
|
||||||
|
expected = {
|
||||||
|
data: { id: '1337', type: 'authors' },
|
||||||
|
meta: { name: 'Dan Brown' }
|
||||||
|
}
|
||||||
|
assert_relationship(:reviewer, expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_with_everything
|
||||||
|
expected = {
|
||||||
|
data: [{ id: '1337', type: 'likes' }],
|
||||||
|
links: {
|
||||||
|
related: {
|
||||||
|
href: '//example.com/likes/1337',
|
||||||
|
meta: { ids: '1337' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
meta: { liked: true }
|
||||||
|
}
|
||||||
|
assert_relationship(:likes, expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def assert_relationship(relationship_name, expected)
|
||||||
|
hash = serializable(@author, adapter: :json_api).serializable_hash
|
||||||
|
assert_equal(expected, hash[:data][:relationships][relationship_name])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
68
test/adapter/json_api/resource_meta_test.rb
Normal file
68
test/adapter/json_api/resource_meta_test.rb
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
module Adapter
|
||||||
|
class JsonApi
|
||||||
|
class ResourceMetaTest < Minitest::Test
|
||||||
|
class MetaHashPostSerializer < ActiveModel::Serializer
|
||||||
|
attributes :id
|
||||||
|
meta stuff: 'value'
|
||||||
|
end
|
||||||
|
|
||||||
|
class MetaBlockPostSerializer < ActiveModel::Serializer
|
||||||
|
attributes :id
|
||||||
|
meta do
|
||||||
|
{ comments_count: object.comments.count }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup
|
||||||
|
@post = Post.new(id: 1337, comments: [], author: nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_meta_hash_object_resource
|
||||||
|
hash = ActiveModel::SerializableResource.new(
|
||||||
|
@post,
|
||||||
|
serializer: MetaHashPostSerializer,
|
||||||
|
adapter: :json_api
|
||||||
|
).serializable_hash
|
||||||
|
expected = {
|
||||||
|
stuff: 'value'
|
||||||
|
}
|
||||||
|
assert_equal(expected, hash[:data][:meta])
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_meta_block_object_resource
|
||||||
|
hash = ActiveModel::SerializableResource.new(
|
||||||
|
@post,
|
||||||
|
serializer: MetaBlockPostSerializer,
|
||||||
|
adapter: :json_api
|
||||||
|
).serializable_hash
|
||||||
|
expected = {
|
||||||
|
comments_count: @post.comments.count
|
||||||
|
}
|
||||||
|
assert_equal(expected, hash[:data][:meta])
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_meta_object_resource_in_array
|
||||||
|
post2 = Post.new(id: 1339, comments: [Comment.new])
|
||||||
|
posts = [@post, post2]
|
||||||
|
hash = ActiveModel::SerializableResource.new(
|
||||||
|
posts,
|
||||||
|
each_serializer: MetaBlockPostSerializer,
|
||||||
|
adapter: :json_api
|
||||||
|
).serializable_hash
|
||||||
|
expected = {
|
||||||
|
:data => [
|
||||||
|
{ :id => '1337', :type => 'posts', :meta => { :comments_count => 0 } },
|
||||||
|
{ :id => '1339', :type => 'posts', :meta => { :comments_count => 1 } }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
assert_equal(expected, hash)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -1,69 +0,0 @@
|
|||||||
require 'test_helper'
|
|
||||||
|
|
||||||
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 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
|
|
||||||
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
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def serializable(resource, options = {})
|
|
||||||
ActiveModel::SerializableResource.new(resource, options)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
61
test/adapter/json_api/type_test.rb
Normal file
61
test/adapter/json_api/type_test.rb
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
module Adapter
|
||||||
|
class JsonApi
|
||||||
|
class TypeTest < ActiveSupport::TestCase
|
||||||
|
class StringTypeSerializer < ActiveModel::Serializer
|
||||||
|
attribute :name
|
||||||
|
type 'profile'
|
||||||
|
end
|
||||||
|
|
||||||
|
class SymbolTypeSerializer < ActiveModel::Serializer
|
||||||
|
attribute :name
|
||||||
|
type :profile
|
||||||
|
end
|
||||||
|
|
||||||
|
setup do
|
||||||
|
@author = Author.new(id: 1, name: 'Steve K.')
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_config_plural
|
||||||
|
with_jsonapi_resource_type :plural do
|
||||||
|
assert_type(@author, 'authors')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_config_singular
|
||||||
|
with_jsonapi_resource_type :singular do
|
||||||
|
assert_type(@author, 'author')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_explicit_string_type_value
|
||||||
|
assert_type(@author, 'profile', serializer: StringTypeSerializer)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_explicit_symbol_type_value
|
||||||
|
assert_type(@author, 'profile', serializer: SymbolTypeSerializer)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def assert_type(resource, expected_type, opts = {})
|
||||||
|
opts = opts.reverse_merge(adapter: :json_api)
|
||||||
|
hash = serializable(resource, opts).serializable_hash
|
||||||
|
assert_equal(expected_type, hash.fetch(:data).fetch(:type))
|
||||||
|
end
|
||||||
|
|
||||||
|
def with_jsonapi_resource_type inflection
|
||||||
|
old_inflection = ActiveModelSerializers.config.jsonapi_resource_type
|
||||||
|
ActiveModelSerializers.config.jsonapi_resource_type = inflection
|
||||||
|
yield
|
||||||
|
ensure
|
||||||
|
ActiveModelSerializers.config.jsonapi_resource_type = old_inflection
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -23,5 +23,13 @@ module ActiveModel
|
|||||||
options = nil
|
options = nil
|
||||||
assert_equal @adapter.as_json(options), @serializable_resource.as_json(options)
|
assert_equal @adapter.as_json(options), @serializable_resource.as_json(options)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_use_adapter_with_adapter_option
|
||||||
|
assert ActiveModel::SerializableResource.new(@resource, { adapter: 'json' }).use_adapter?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_use_adapter_with_adapter_option_as_false
|
||||||
|
refute ActiveModel::SerializableResource.new(@resource, { adapter: false }).use_adapter?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -32,13 +32,13 @@ module ActiveModel
|
|||||||
|
|
||||||
case key
|
case key
|
||||||
when :posts
|
when :posts
|
||||||
assert_equal({}, options)
|
assert_equal({ include_data: true }, options)
|
||||||
assert_kind_of(ActiveModelSerializers.config.collection_serializer, serializer)
|
assert_kind_of(ActiveModelSerializers.config.collection_serializer, serializer)
|
||||||
when :bio
|
when :bio
|
||||||
assert_equal({}, options)
|
assert_equal({ include_data: true }, options)
|
||||||
assert_nil serializer
|
assert_nil serializer
|
||||||
when :roles
|
when :roles
|
||||||
assert_equal({}, options)
|
assert_equal({ include_data: true }, options)
|
||||||
assert_kind_of(ActiveModelSerializers.config.collection_serializer, serializer)
|
assert_kind_of(ActiveModelSerializers.config.collection_serializer, serializer)
|
||||||
else
|
else
|
||||||
flunk "Unknown association: #{key}"
|
flunk "Unknown association: #{key}"
|
||||||
@ -80,7 +80,7 @@ module ActiveModel
|
|||||||
flunk "Unknown association: #{key}"
|
flunk "Unknown association: #{key}"
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal({}, association.options)
|
assert_equal({ include_data: true }, association.options)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -1,209 +1,238 @@
|
|||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
require 'tmpdir'
|
require 'tmpdir'
|
||||||
require 'tempfile'
|
require 'tempfile'
|
||||||
module ActiveModel
|
module ActiveModelSerializers
|
||||||
class Serializer
|
class CacheTest < ActiveSupport::TestCase
|
||||||
class CacheTest < ActiveSupport::TestCase
|
include ActiveSupport::Testing::Stream
|
||||||
include ActiveSupport::Testing::Stream
|
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
ActionController::Base.cache_store.clear
|
ActionController::Base.cache_store.clear
|
||||||
@comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
@comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
||||||
@post = Post.new(title: 'New Post', body: 'Body')
|
@post = Post.new(title: 'New Post', body: 'Body')
|
||||||
@bio = Bio.new(id: 1, content: 'AMS Contributor')
|
@bio = Bio.new(id: 1, content: 'AMS Contributor')
|
||||||
@author = Author.new(name: 'Joao M. D. Moura')
|
@author = Author.new(name: 'Joao M. D. Moura')
|
||||||
@blog = Blog.new(id: 999, name: 'Custom blog', writer: @author, articles: [])
|
@blog = Blog.new(id: 999, name: 'Custom blog', writer: @author, articles: [])
|
||||||
@role = Role.new(name: 'Great Author')
|
@role = Role.new(name: 'Great Author')
|
||||||
@location = Location.new(lat: '-23.550520', lng: '-46.633309')
|
@location = Location.new(lat: '-23.550520', lng: '-46.633309')
|
||||||
@place = Place.new(name: 'Amazing Place')
|
@place = Place.new(name: 'Amazing Place')
|
||||||
@author.posts = [@post]
|
@author.posts = [@post]
|
||||||
@author.roles = [@role]
|
@author.roles = [@role]
|
||||||
@role.author = @author
|
@role.author = @author
|
||||||
@author.bio = @bio
|
@author.bio = @bio
|
||||||
@bio.author = @author
|
@bio.author = @author
|
||||||
@post.comments = [@comment]
|
@post.comments = [@comment]
|
||||||
@post.author = @author
|
@post.author = @author
|
||||||
@comment.post = @post
|
@comment.post = @post
|
||||||
@comment.author = @author
|
@comment.author = @author
|
||||||
@post.blog = @blog
|
@post.blog = @blog
|
||||||
@location.place = @place
|
@location.place = @place
|
||||||
|
|
||||||
@location_serializer = LocationSerializer.new(@location)
|
@location_serializer = LocationSerializer.new(@location)
|
||||||
@bio_serializer = BioSerializer.new(@bio)
|
@bio_serializer = BioSerializer.new(@bio)
|
||||||
@role_serializer = RoleSerializer.new(@role)
|
@role_serializer = RoleSerializer.new(@role)
|
||||||
@post_serializer = PostSerializer.new(@post)
|
@post_serializer = PostSerializer.new(@post)
|
||||||
@author_serializer = AuthorSerializer.new(@author)
|
@author_serializer = AuthorSerializer.new(@author)
|
||||||
@comment_serializer = CommentSerializer.new(@comment)
|
@comment_serializer = CommentSerializer.new(@comment)
|
||||||
@blog_serializer = BlogSerializer.new(@blog)
|
@blog_serializer = BlogSerializer.new(@blog)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_inherited_cache_configuration
|
||||||
|
inherited_serializer = Class.new(PostSerializer)
|
||||||
|
|
||||||
|
assert_equal PostSerializer._cache_key, inherited_serializer._cache_key
|
||||||
|
assert_equal PostSerializer._cache_options, inherited_serializer._cache_options
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_override_cache_configuration
|
||||||
|
inherited_serializer = Class.new(PostSerializer) do
|
||||||
|
cache key: 'new-key'
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_inherited_cache_configuration
|
assert_equal PostSerializer._cache_key, 'post'
|
||||||
inherited_serializer = Class.new(PostSerializer)
|
assert_equal inherited_serializer._cache_key, 'new-key'
|
||||||
|
end
|
||||||
|
|
||||||
assert_equal PostSerializer._cache_key, inherited_serializer._cache_key
|
def test_cache_definition
|
||||||
assert_equal PostSerializer._cache_options, inherited_serializer._cache_options
|
assert_equal(ActionController::Base.cache_store, @post_serializer.class._cache)
|
||||||
|
assert_equal(ActionController::Base.cache_store, @author_serializer.class._cache)
|
||||||
|
assert_equal(ActionController::Base.cache_store, @comment_serializer.class._cache)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cache_key_definition
|
||||||
|
assert_equal('post', @post_serializer.class._cache_key)
|
||||||
|
assert_equal('writer', @author_serializer.class._cache_key)
|
||||||
|
assert_equal(nil, @comment_serializer.class._cache_key)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cache_key_interpolation_with_updated_at
|
||||||
|
render_object_with_cache(@author)
|
||||||
|
assert_equal(nil, ActionController::Base.cache_store.fetch(@author.cache_key))
|
||||||
|
assert_equal(@author_serializer.attributes.to_json, ActionController::Base.cache_store.fetch("#{@author_serializer.class._cache_key}/#{@author_serializer.object.id}-#{@author_serializer.object.updated_at.strftime("%Y%m%d%H%M%S%9N")}").to_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_default_cache_key_fallback
|
||||||
|
render_object_with_cache(@comment)
|
||||||
|
assert_equal(@comment_serializer.attributes.to_json, ActionController::Base.cache_store.fetch(@comment.cache_key).to_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cache_options_definition
|
||||||
|
assert_equal({ expires_in: 0.1, skip_digest: true }, @post_serializer.class._cache_options)
|
||||||
|
assert_equal(nil, @blog_serializer.class._cache_options)
|
||||||
|
assert_equal({ expires_in: 1.day, skip_digest: true }, @comment_serializer.class._cache_options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_fragment_cache_definition
|
||||||
|
assert_equal([:name], @role_serializer.class._cache_only)
|
||||||
|
assert_equal([:content], @bio_serializer.class._cache_except)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_separately_cache
|
||||||
|
ActionController::Base.cache_store.clear
|
||||||
|
assert_equal(nil, ActionController::Base.cache_store.fetch(@post.cache_key))
|
||||||
|
assert_equal(nil, ActionController::Base.cache_store.fetch(@comment.cache_key))
|
||||||
|
|
||||||
|
Timecop.freeze(Time.now) do
|
||||||
|
render_object_with_cache(@post)
|
||||||
|
|
||||||
|
assert_equal(@post_serializer.attributes, ActionController::Base.cache_store.fetch(@post.cache_key))
|
||||||
|
assert_equal(@comment_serializer.attributes, ActionController::Base.cache_store.fetch(@comment.cache_key))
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_override_cache_configuration
|
def test_associations_cache_when_updated
|
||||||
inherited_serializer = Class.new(PostSerializer) do
|
# Clean the Cache
|
||||||
cache key: 'new-key'
|
ActionController::Base.cache_store.clear
|
||||||
end
|
|
||||||
|
|
||||||
assert_equal PostSerializer._cache_key, 'post'
|
Timecop.freeze(Time.now) do
|
||||||
assert_equal inherited_serializer._cache_key, 'new-key'
|
# Generate a new Cache of Post object and each objects related to it.
|
||||||
|
render_object_with_cache(@post)
|
||||||
|
|
||||||
|
# Check if it cached the objects separately
|
||||||
|
assert_equal(@post_serializer.attributes, ActionController::Base.cache_store.fetch(@post.cache_key))
|
||||||
|
assert_equal(@comment_serializer.attributes, ActionController::Base.cache_store.fetch(@comment.cache_key))
|
||||||
|
|
||||||
|
# Simulating update on comments relationship with Post
|
||||||
|
new_comment = Comment.new(id: 2, body: 'ZOMG A NEW COMMENT')
|
||||||
|
new_comment_serializer = CommentSerializer.new(new_comment)
|
||||||
|
@post.comments = [new_comment]
|
||||||
|
|
||||||
|
# Ask for the serialized object
|
||||||
|
render_object_with_cache(@post)
|
||||||
|
|
||||||
|
# Check if the the new comment was cached
|
||||||
|
assert_equal(new_comment_serializer.attributes, ActionController::Base.cache_store.fetch(new_comment.cache_key))
|
||||||
|
assert_equal(@post_serializer.attributes, ActionController::Base.cache_store.fetch(@post.cache_key))
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_cache_definition
|
def test_fragment_fetch_with_virtual_associations
|
||||||
assert_equal(ActionController::Base.cache_store, @post_serializer.class._cache)
|
expected_result = {
|
||||||
assert_equal(ActionController::Base.cache_store, @author_serializer.class._cache)
|
id: @location.id,
|
||||||
assert_equal(ActionController::Base.cache_store, @comment_serializer.class._cache)
|
lat: @location.lat,
|
||||||
end
|
lng: @location.lng,
|
||||||
|
place: 'Nowhere'
|
||||||
|
}
|
||||||
|
|
||||||
def test_cache_key_definition
|
hash = render_object_with_cache(@location)
|
||||||
assert_equal('post', @post_serializer.class._cache_key)
|
|
||||||
assert_equal('writer', @author_serializer.class._cache_key)
|
|
||||||
assert_equal(nil, @comment_serializer.class._cache_key)
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_cache_key_interpolation_with_updated_at
|
assert_equal(hash, expected_result)
|
||||||
render_object_with_cache(@author)
|
assert_equal({ place: 'Nowhere' }, ActionController::Base.cache_store.fetch(@location.cache_key))
|
||||||
assert_equal(nil, ActionController::Base.cache_store.fetch(@author.cache_key))
|
end
|
||||||
assert_equal(@author_serializer.attributes.to_json, ActionController::Base.cache_store.fetch("#{@author_serializer.class._cache_key}/#{@author_serializer.object.id}-#{@author_serializer.object.updated_at.strftime("%Y%m%d%H%M%S%9N")}").to_json)
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_default_cache_key_fallback
|
def test_uses_file_digest_in_cache_key
|
||||||
|
render_object_with_cache(@blog)
|
||||||
|
assert_equal(@blog_serializer.attributes, ActionController::Base.cache_store.fetch(@blog.cache_key_with_digest))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cache_digest_definition
|
||||||
|
assert_equal(::Model::FILE_DIGEST, @post_serializer.class._cache_digest)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_object_cache_keys
|
||||||
|
serializer = ActiveModel::Serializer::CollectionSerializer.new([@comment, @comment])
|
||||||
|
include_tree = ActiveModel::Serializer::IncludeTree.from_include_args('*')
|
||||||
|
|
||||||
|
actual = Adapter::CachedSerializer.object_cache_keys(serializer, include_tree)
|
||||||
|
|
||||||
|
assert_equal actual.size, 3
|
||||||
|
assert actual.any? { |key| key == 'comment/1' }
|
||||||
|
assert actual.any? { |key| key =~ %r{post/post-\d+} }
|
||||||
|
assert actual.any? { |key| key =~ %r{writer/author-\d+} }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cached_attributes
|
||||||
|
serializer = ActiveModel::Serializer::CollectionSerializer.new([@comment, @comment])
|
||||||
|
|
||||||
|
Timecop.freeze(Time.now) do
|
||||||
render_object_with_cache(@comment)
|
render_object_with_cache(@comment)
|
||||||
assert_equal(@comment_serializer.attributes.to_json, ActionController::Base.cache_store.fetch(@comment.cache_key).to_json)
|
|
||||||
|
attributes = Adapter::Attributes.new(serializer)
|
||||||
|
attributes.send(:cache_attributes)
|
||||||
|
cached_attributes = attributes.instance_variable_get(:@cached_attributes)
|
||||||
|
|
||||||
|
assert_equal cached_attributes[@comment.cache_key], Comment.new(id: 1, body: 'ZOMG A COMMENT').attributes
|
||||||
|
assert_equal cached_attributes[@comment.post.cache_key], Post.new(id: 'post', title: 'New Post', body: 'Body').attributes
|
||||||
|
|
||||||
|
writer = @comment.post.blog.writer
|
||||||
|
writer_cache_key = "writer/#{writer.id}-#{writer.updated_at.strftime("%Y%m%d%H%M%S%9N")}"
|
||||||
|
|
||||||
|
assert_equal cached_attributes[writer_cache_key], Author.new(id: 'author', name: 'Joao M. D. Moura').attributes
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_cache_options_definition
|
def test_serializer_file_path_on_nix
|
||||||
assert_equal({ expires_in: 0.1, skip_digest: true }, @post_serializer.class._cache_options)
|
path = '/Users/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb'
|
||||||
assert_equal(nil, @blog_serializer.class._cache_options)
|
caller_line = "#{path}:1:in `<top (required)>'"
|
||||||
assert_equal({ expires_in: 1.day, skip_digest: true }, @comment_serializer.class._cache_options)
|
assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_fragment_cache_definition
|
def test_serializer_file_path_on_windows
|
||||||
assert_equal([:name], @role_serializer.class._cache_only)
|
path = 'c:/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb'
|
||||||
assert_equal([:content], @bio_serializer.class._cache_except)
|
caller_line = "#{path}:1:in `<top (required)>'"
|
||||||
end
|
assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
|
||||||
|
end
|
||||||
|
|
||||||
def test_associations_separately_cache
|
def test_serializer_file_path_with_space
|
||||||
ActionController::Base.cache_store.clear
|
path = '/Users/git/ember js/ember-crm-backend/app/serializers/lead_serializer.rb'
|
||||||
assert_equal(nil, ActionController::Base.cache_store.fetch(@post.cache_key))
|
caller_line = "#{path}:1:in `<top (required)>'"
|
||||||
assert_equal(nil, ActionController::Base.cache_store.fetch(@comment.cache_key))
|
assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
|
||||||
|
end
|
||||||
|
|
||||||
Timecop.freeze(Time.now) do
|
def test_serializer_file_path_with_submatch
|
||||||
render_object_with_cache(@post)
|
# The submatch in the path ensures we're using a correctly greedy regexp.
|
||||||
|
path = '/Users/git/ember js/ember:123:in x/app/serializers/lead_serializer.rb'
|
||||||
|
caller_line = "#{path}:1:in `<top (required)>'"
|
||||||
|
assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
|
||||||
|
end
|
||||||
|
|
||||||
assert_equal(@post_serializer.attributes, ActionController::Base.cache_store.fetch(@post.cache_key))
|
def test_digest_caller_file
|
||||||
assert_equal(@comment_serializer.attributes, ActionController::Base.cache_store.fetch(@comment.cache_key))
|
contents = "puts 'AMS rocks'!"
|
||||||
end
|
dir = Dir.mktmpdir('space char')
|
||||||
end
|
file = Tempfile.new('some_ruby.rb', dir)
|
||||||
|
file.write(contents)
|
||||||
|
path = file.path
|
||||||
|
caller_line = "#{path}:1:in `<top (required)>'"
|
||||||
|
file.close
|
||||||
|
assert_equal ActiveModel::Serializer.digest_caller_file(caller_line), Digest::MD5.hexdigest(contents)
|
||||||
|
ensure
|
||||||
|
file.unlink
|
||||||
|
FileUtils.remove_entry dir
|
||||||
|
end
|
||||||
|
|
||||||
def test_associations_cache_when_updated
|
def test_warn_on_serializer_not_defined_in_file
|
||||||
# Clean the Cache
|
called = false
|
||||||
ActionController::Base.cache_store.clear
|
serializer = Class.new(ActiveModel::Serializer)
|
||||||
|
assert_match(/_cache_digest/, (capture(:stderr) do
|
||||||
|
serializer.digest_caller_file('')
|
||||||
|
called = true
|
||||||
|
end))
|
||||||
|
assert called
|
||||||
|
end
|
||||||
|
|
||||||
Timecop.freeze(Time.now) do
|
private
|
||||||
# Generate a new Cache of Post object and each objects related to it.
|
|
||||||
render_object_with_cache(@post)
|
|
||||||
|
|
||||||
# Check if it cached the objects separately
|
def render_object_with_cache(obj)
|
||||||
assert_equal(@post_serializer.attributes, ActionController::Base.cache_store.fetch(@post.cache_key))
|
ActiveModel::SerializableResource.new(obj).serializable_hash
|
||||||
assert_equal(@comment_serializer.attributes, ActionController::Base.cache_store.fetch(@comment.cache_key))
|
|
||||||
|
|
||||||
# Simulating update on comments relationship with Post
|
|
||||||
new_comment = Comment.new(id: 2, body: 'ZOMG A NEW COMMENT')
|
|
||||||
new_comment_serializer = CommentSerializer.new(new_comment)
|
|
||||||
@post.comments = [new_comment]
|
|
||||||
|
|
||||||
# Ask for the serialized object
|
|
||||||
render_object_with_cache(@post)
|
|
||||||
|
|
||||||
# Check if the the new comment was cached
|
|
||||||
assert_equal(new_comment_serializer.attributes, ActionController::Base.cache_store.fetch(new_comment.cache_key))
|
|
||||||
assert_equal(@post_serializer.attributes, ActionController::Base.cache_store.fetch(@post.cache_key))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_fragment_fetch_with_virtual_associations
|
|
||||||
expected_result = {
|
|
||||||
id: @location.id,
|
|
||||||
lat: @location.lat,
|
|
||||||
lng: @location.lng,
|
|
||||||
place: 'Nowhere'
|
|
||||||
}
|
|
||||||
|
|
||||||
hash = render_object_with_cache(@location)
|
|
||||||
|
|
||||||
assert_equal(hash, expected_result)
|
|
||||||
assert_equal({ place: 'Nowhere' }, ActionController::Base.cache_store.fetch(@location.cache_key))
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_uses_file_digest_in_cache_key
|
|
||||||
render_object_with_cache(@blog)
|
|
||||||
assert_equal(@blog_serializer.attributes, ActionController::Base.cache_store.fetch(@blog.cache_key_with_digest))
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_cache_digest_definition
|
|
||||||
assert_equal(::Model::FILE_DIGEST, @post_serializer.class._cache_digest)
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_serializer_file_path_on_nix
|
|
||||||
path = '/Users/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb'
|
|
||||||
caller_line = "#{path}:1:in `<top (required)>'"
|
|
||||||
assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_serializer_file_path_on_windows
|
|
||||||
path = 'c:/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb'
|
|
||||||
caller_line = "#{path}:1:in `<top (required)>'"
|
|
||||||
assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_serializer_file_path_with_space
|
|
||||||
path = '/Users/git/ember js/ember-crm-backend/app/serializers/lead_serializer.rb'
|
|
||||||
caller_line = "#{path}:1:in `<top (required)>'"
|
|
||||||
assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_serializer_file_path_with_submatch
|
|
||||||
# The submatch in the path ensures we're using a correctly greedy regexp.
|
|
||||||
path = '/Users/git/ember js/ember:123:in x/app/serializers/lead_serializer.rb'
|
|
||||||
caller_line = "#{path}:1:in `<top (required)>'"
|
|
||||||
assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_digest_caller_file
|
|
||||||
contents = "puts 'AMS rocks'!"
|
|
||||||
dir = Dir.mktmpdir('space char')
|
|
||||||
file = Tempfile.new('some_ruby.rb', dir)
|
|
||||||
file.write(contents)
|
|
||||||
path = file.path
|
|
||||||
caller_line = "#{path}:1:in `<top (required)>'"
|
|
||||||
file.close
|
|
||||||
assert_equal ActiveModel::Serializer.digest_caller_file(caller_line), Digest::MD5.hexdigest(contents)
|
|
||||||
ensure
|
|
||||||
file.unlink
|
|
||||||
FileUtils.remove_entry dir
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_warn_on_serializer_not_defined_in_file
|
|
||||||
called = false
|
|
||||||
serializer = Class.new(ActiveModel::Serializer)
|
|
||||||
assert_match(/_cache_digest/, (capture(:stderr) do
|
|
||||||
serializer.digest_caller_file('')
|
|
||||||
called = true
|
|
||||||
end))
|
|
||||||
assert called
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def render_object_with_cache(obj)
|
|
||||||
ActiveModel::SerializableResource.new(obj).serializable_hash
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
80
test/serializers/cached_serializer_test.rb
Normal file
80
test/serializers/cached_serializer_test.rb
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
module ActiveModelSerializers
|
||||||
|
module Adapter
|
||||||
|
class CachedSerializerTest < ActiveSupport::TestCase
|
||||||
|
def test_cached_false_without_cache_store
|
||||||
|
cached_serializer = build do |serializer|
|
||||||
|
serializer._cache = nil
|
||||||
|
end
|
||||||
|
refute cached_serializer.cached?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cached_true_with_cache_store_and_without_cache_only_and_cache_except
|
||||||
|
cached_serializer = build do |serializer|
|
||||||
|
serializer._cache = Object
|
||||||
|
end
|
||||||
|
assert cached_serializer.cached?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cached_false_with_cache_store_and_with_cache_only
|
||||||
|
cached_serializer = build do |serializer|
|
||||||
|
serializer._cache = Object
|
||||||
|
serializer._cache_only = [:name]
|
||||||
|
end
|
||||||
|
refute cached_serializer.cached?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cached_false_with_cache_store_and_with_cache_except
|
||||||
|
cached_serializer = build do |serializer|
|
||||||
|
serializer._cache = Object
|
||||||
|
serializer._cache_except = [:content]
|
||||||
|
end
|
||||||
|
refute cached_serializer.cached?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_fragment_cached_false_without_cache_store
|
||||||
|
cached_serializer = build do |serializer|
|
||||||
|
serializer._cache = nil
|
||||||
|
serializer._cache_only = [:name]
|
||||||
|
end
|
||||||
|
refute cached_serializer.fragment_cached?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_fragment_cached_true_with_cache_store_and_cache_only
|
||||||
|
cached_serializer = build do |serializer|
|
||||||
|
serializer._cache = Object
|
||||||
|
serializer._cache_only = [:name]
|
||||||
|
end
|
||||||
|
assert cached_serializer.fragment_cached?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_fragment_cached_true_with_cache_store_and_cache_except
|
||||||
|
cached_serializer = build do |serializer|
|
||||||
|
serializer._cache = Object
|
||||||
|
serializer._cache_except = [:content]
|
||||||
|
end
|
||||||
|
assert cached_serializer.fragment_cached?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_fragment_cached_false_with_cache_store_and_cache_except_and_cache_only
|
||||||
|
cached_serializer = build do |serializer|
|
||||||
|
serializer._cache = Object
|
||||||
|
serializer._cache_except = [:content]
|
||||||
|
serializer._cache_only = [:name]
|
||||||
|
end
|
||||||
|
refute cached_serializer.fragment_cached?
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def build
|
||||||
|
serializer = Class.new(ActiveModel::Serializer)
|
||||||
|
serializer._cache_key = nil
|
||||||
|
serializer._cache_options = nil
|
||||||
|
yield serializer if block_given?
|
||||||
|
serializer_instance = serializer.new(Object)
|
||||||
|
CachedSerializer.new(serializer_instance)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -1,6 +0,0 @@
|
|||||||
# https://github.com/colszowka/simplecov/pull/400
|
|
||||||
# https://github.com/ruby/ruby/blob/trunk/lib/English.rb
|
|
||||||
unless defined?(English)
|
|
||||||
# The exception object passed to +raise+.
|
|
||||||
alias $ERROR_INFO $! # rubocop:disable Style/SpecialGlobalVars
|
|
||||||
end
|
|
||||||
Loading…
Reference in New Issue
Block a user