mirror of
https://github.com/ditkrg/active_model_serializers.git
synced 2026-01-22 22:06:50 +00:00
Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca531789c3 | ||
|
|
c41e243ed8 | ||
|
|
b41451c9bf | ||
|
|
3dd6cccb4d | ||
|
|
00a47d3da4 | ||
|
|
3c5e11bb0f | ||
|
|
33ec26fa12 | ||
|
|
0bbeeb384e | ||
|
|
196216b250 | ||
|
|
51f2643f40 | ||
|
|
9745a2f735 | ||
|
|
5916014b48 | ||
|
|
92dde58f5f | ||
|
|
82e90091fd | ||
|
|
b439fe69c6 | ||
|
|
e3480345e3 | ||
|
|
54d40c79e8 | ||
|
|
c6a14c9eac | ||
|
|
1fd324947f | ||
|
|
a0de45a4d8 | ||
|
|
cf29db34c6 | ||
|
|
0fcb8a6cce | ||
|
|
5e1e138d47 | ||
|
|
4076a480b7 | ||
|
|
88367da970 | ||
|
|
4d7c2457d7 | ||
|
|
715a702f55 | ||
|
|
4a995955ea | ||
|
|
ab517d1a2d | ||
|
|
1c9214d041 | ||
|
|
6a7d864605 | ||
|
|
c2fa01624d | ||
|
|
4f78319219 | ||
|
|
b1de431731 | ||
|
|
967ff8dcc0 | ||
|
|
1e4d117b99 | ||
|
|
402883d84f | ||
|
|
e4b3224c64 | ||
|
|
b7442e741c | ||
|
|
1539747a59 | ||
|
|
622872ae2b | ||
|
|
92e9a66e97 | ||
|
|
16e5204eab | ||
|
|
ff71ef26eb | ||
|
|
d8e983604b | ||
|
|
7387266c37 | ||
|
|
a89e78c655 | ||
|
|
a5ab62fd18 | ||
|
|
be7ee70376 | ||
|
|
b48aeeef1e | ||
|
|
01d4f0464b | ||
|
|
f353dedf28 | ||
|
|
db617b8bf9 | ||
|
|
9a2f4894ed | ||
|
|
4c6f104ae9 | ||
|
|
1570437795 | ||
|
|
ec1022ecb3 | ||
|
|
b5f886cb95 | ||
|
|
ec905d8179 | ||
|
|
c25f2f3863 | ||
|
|
4e6bd61350 | ||
|
|
d5babdd060 | ||
|
|
85dfef9072 | ||
|
|
59aed4d00e | ||
|
|
a5423dab20 | ||
|
|
9a2e1e4743 | ||
|
|
0dd7680fe5 | ||
|
|
21bcfd891d | ||
|
|
82db1301f6 | ||
|
|
23f03ffd30 | ||
|
|
97b587b14c | ||
|
|
adf110f4df | ||
|
|
2c0b15d22f | ||
|
|
dfa6caac27 | ||
|
|
49f2dca730 | ||
|
|
4054f43309 | ||
|
|
e036b71e0c | ||
|
|
6e11d6234e |
59
.travis.yml
59
.travis.yml
@ -1,55 +1,52 @@
|
||||
language: ruby
|
||||
|
||||
sudo: false
|
||||
|
||||
rvm:
|
||||
- 2.1
|
||||
- 2.2.6
|
||||
- 2.3.3
|
||||
- ruby-head
|
||||
- jruby-9.1.5.0 # is precompiled per http://rubies.travis-ci.org/
|
||||
- jruby-head
|
||||
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
|
||||
before_install:
|
||||
- gem update --system
|
||||
- rvm @global do gem uninstall bundler -a -x
|
||||
- rvm @global do gem install bundler -v 1.13.7
|
||||
install: bundle install --path=vendor/bundle --retry=3 --jobs=3
|
||||
cache:
|
||||
directories:
|
||||
- vendor/bundle
|
||||
|
||||
before_install:
|
||||
- "travis_retry gem update --system"
|
||||
- "travis_retry gem update bundler"
|
||||
install: bundle install --path=vendor/bundle --retry=3 --jobs=3
|
||||
|
||||
script:
|
||||
- bundle exec rake ci
|
||||
after_success:
|
||||
- codeclimate-test-reporter
|
||||
|
||||
env:
|
||||
global:
|
||||
- "JRUBY_OPTS='--dev -J-Xmx1024M --debug'"
|
||||
matrix:
|
||||
- "RAILS_VERSION=4.1"
|
||||
- "RAILS_VERSION=4.2"
|
||||
- "RAILS_VERSION=5.0"
|
||||
- "RAILS_VERSION=5.1"
|
||||
- "RAILS_VERSION=master"
|
||||
|
||||
rvm:
|
||||
- 2.1.10
|
||||
- 2.2.8
|
||||
- 2.3.5
|
||||
- 2.4.2
|
||||
- ruby-head
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- { rvm: jruby-9.1.13.0, jdk: oraclejdk8, env: "RAILS_VERSION=4.1 JRUBY_OPTS='--dev -J-Xmx1024M --debug'" }
|
||||
- { rvm: jruby-9.1.13.0, jdk: oraclejdk8, env: "RAILS_VERSION=4.2 JRUBY_OPTS='--dev -J-Xmx1024M --debug'" }
|
||||
- { rvm: jruby-9.1.13.0, jdk: oraclejdk8, env: "RAILS_VERSION=5.1 JRUBY_OPTS='--dev -J-Xmx1024M --debug'" }
|
||||
# See JRuby currently failing on Rails 5+ https://github.com/jruby/activerecord-jdbc-adapter/issues/708
|
||||
# - { rvm: jruby-9.1.13.0, jdk: oraclejdk8, env: "RAILS_VERSION=5.0 JRUBY_OPTS='--dev -J-Xmx1024M --debug'" }
|
||||
# - { rvm: jruby-head, jdk: oraclejdk8, env: "RAILS_VERSION=5.1 JRUBY_OPTS='--dev -J-Xmx1024M --debug'" }
|
||||
exclude:
|
||||
- rvm: 2.1
|
||||
env: RAILS_VERSION=master
|
||||
- rvm: jruby-9.1.5.0
|
||||
env: RAILS_VERSION=master
|
||||
- rvm: jruby-head
|
||||
env: RAILS_VERSION=master
|
||||
- rvm: 2.1
|
||||
env: RAILS_VERSION=5.0
|
||||
- rvm: jruby-9.1.5.0
|
||||
env: RAILS_VERSION=5.0
|
||||
- rvm: jruby-head
|
||||
env: RAILS_VERSION=5.0
|
||||
- { rvm: 2.1.10, env: RAILS_VERSION=master }
|
||||
- { rvm: 2.1.10, env: RAILS_VERSION=5.0 }
|
||||
- { rvm: 2.1.10, env: RAILS_VERSION=5.1 }
|
||||
- { rvm: 2.4.2, env: RAILS_VERSION=4.1 }
|
||||
- { rvm: ruby-head, env: RAILS_VERSION=4.1 }
|
||||
allow_failures:
|
||||
- rvm: ruby-head
|
||||
- rvm: jruby-head
|
||||
# See JRuby currently failing on Rails 5+ https://github.com/jruby/activerecord-jdbc-adapter/issues/708
|
||||
- { rvm: jruby-9.1.13.0, jdk: oraclejdk8, env: "RAILS_VERSION=5.1 JRUBY_OPTS='--dev -J-Xmx1024M --debug'" }
|
||||
fast_finish: true
|
||||
|
||||
48
CHANGELOG.md
48
CHANGELOG.md
@ -1,6 +1,6 @@
|
||||
## 0.10.x
|
||||
|
||||
### [master (unreleased)](https://github.com/rails-api/active_model_serializers/compare/v0.10.6...master)
|
||||
### [master (unreleased)](https://github.com/rails-api/active_model_serializers/compare/v0.10.7...0-10-stable)
|
||||
|
||||
Breaking changes:
|
||||
|
||||
@ -10,6 +10,52 @@ Fixes:
|
||||
|
||||
Misc:
|
||||
|
||||
### [v0.10.7 (2017-11-14)](https://github.com/rails-api/active_model_serializers/compare/v0.10.6...v0.10.7)
|
||||
|
||||
Regressions Fixed From v0.10.6:
|
||||
|
||||
- [#2211](https://github.com/rails-api/active_model_serializers/pull/2211). Fixes #2125, #2160. (@bf4)
|
||||
- Fix polymorphic belongs_to tests; passes on v0.10.5, fails on v0.10.6
|
||||
- Fix JSON:API polymorphic type regression from v0.10.5
|
||||
- Fix JSON:API: for_type_and_id should always inflect_type
|
||||
```
|
||||
Should Serializer._type ever be inflected?
|
||||
Right now, it won't be, but association.serializer._type will be inflected.
|
||||
|
||||
That's the current behavior.
|
||||
```
|
||||
- [#2216](https://github.com/rails-api/active_model_serializers/pull/2216). Fixes #2132, #2180. (@bf4)
|
||||
- Fix JSON:API: Serialize resource type for unpersisted records (blank id)
|
||||
- [#2218](https://github.com/rails-api/active_model_serializers/pull/2218). Fixes #2178. (@bf4)
|
||||
- Fix JSON:API: Make using foreign key on belongs_to opt-in. No effect on polymorphic relationships.
|
||||
```
|
||||
# set to true to opt-in
|
||||
ActiveModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship = true
|
||||
```
|
||||
|
||||
Features:
|
||||
|
||||
- [#2136](https://github.com/rails-api/active_model_serializers/pull/2136) Enable inclusion of sideloaded relationship objects by `key`. (@caomania)
|
||||
- [#2021](https://github.com/rails-api/active_model_serializers/pull/2021) ActiveModelSerializers::Model#attributes. Originally in [#1982](https://github.com/rails-api/active_model_serializers/pull/1982). (@bf4)
|
||||
- [#2130](https://github.com/rails-api/active_model_serializers/pull/2130) Allow serialized ID to be overwritten for belongs-to relationships. (@greysteil)
|
||||
- [#2189](https://github.com/rails-api/active_model_serializers/pull/2189)
|
||||
Update version constraint for jsonapi-renderer to `['>= 0.1.1.beta1', '< 0.3']`
|
||||
(@tagliala)
|
||||
|
||||
Fixes:
|
||||
|
||||
- [#2022](https://github.com/rails-api/active_model_serializers/pull/2022) Mutation of ActiveModelSerializers::Model now changes the attributes. Originally in [#1984](https://github.com/rails-api/active_model_serializers/pull/1984). (@bf4)
|
||||
- [#2200](https://github.com/rails-api/active_model_serializers/pull/2200) Fix deserialization of polymorphic relationships. (@dennis95stumm)
|
||||
- [#2214](https://github.com/rails-api/active_model_serializers/pull/2214) Fail if unable to infer collection type with json adapter. (@jmeredith16)
|
||||
- [#2149](https://github.com/rails-api/active_model_serializers/pull/2149) Always include self, first, last pagination link. (@mecampbellsoup)
|
||||
- [#2179](https://github.com/rails-api/active_model_serializers/pull/2179) Fixes #2173, Pass block to Enumerator.new. (@drn)
|
||||
|
||||
Misc:
|
||||
|
||||
- [#2176](https://github.com/rails-api/active_model_serializers/pull/2176) Documentation for global adapter config. (@mrpinsky)
|
||||
- [#2215](https://github.com/rails-api/active_model_serializers/pull/2215) Update `serializers.md` documentation to denote alternate use cases for `scope`. (@stratigos)
|
||||
- [#2212](https://github.com/rails-api/active_model_serializers/pull/2212) Remove legacy has_many_embed_ids test. (@bf4)
|
||||
|
||||
### [v0.10.6 (2017-05-01)](https://github.com/rails-api/active_model_serializers/compare/v0.10.5...v0.10.6)
|
||||
|
||||
Fixes:
|
||||
|
||||
22
Gemfile
22
Gemfile
@ -12,6 +12,7 @@ version = ENV['RAILS_VERSION'] || '4.2'
|
||||
if version == 'master'
|
||||
gem 'rack', github: 'rack/rack'
|
||||
gem 'arel', github: 'rails/arel'
|
||||
gem 'rails', github: 'rails/rails'
|
||||
git 'https://github.com/rails/rails.git' do
|
||||
gem 'railties'
|
||||
gem 'activesupport'
|
||||
@ -23,6 +24,7 @@ if version == 'master'
|
||||
end
|
||||
else
|
||||
gem_version = "~> #{version}.0"
|
||||
gem 'rails', gem_version
|
||||
gem 'railties', gem_version
|
||||
gem 'activesupport', gem_version
|
||||
gem 'activemodel', gem_version
|
||||
@ -36,6 +38,13 @@ end
|
||||
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
|
||||
gem 'tzinfo-data', platforms: (@windows_platforms + [:jruby])
|
||||
|
||||
if ENV['CI']
|
||||
if RUBY_VERSION < '2.4'
|
||||
# Windows: An error occurred while installing nokogiri (1.8.0)
|
||||
gem 'nokogiri', '< 1.7', platforms: @windows_platforms
|
||||
end
|
||||
end
|
||||
|
||||
group :bench do
|
||||
# https://github.com/rails-api/active_model_serializers/commit/cb4459580a6f4f37f629bf3185a5224c8624ca76
|
||||
gem 'benchmark-ips', '>= 2.7.2', require: false, group: :development
|
||||
@ -43,11 +52,18 @@ end
|
||||
|
||||
group :test do
|
||||
gem 'sqlite3', platform: (@windows_platforms + [:ruby])
|
||||
gem 'activerecord-jdbcsqlite3-adapter', platform: :jruby
|
||||
platforms :jruby do
|
||||
if version == 'master' || version >= '5'
|
||||
gem 'activerecord-jdbcsqlite3-adapter', '>= 1.3.0' # github: 'jruby/activerecord-jdbc-adapter', branch: 'master'
|
||||
else
|
||||
gem 'activerecord-jdbcsqlite3-adapter'
|
||||
end
|
||||
end
|
||||
gem 'codeclimate-test-reporter', require: false
|
||||
gem 'm', '~> 1.5'
|
||||
gem 'pry', '~> 0.10'
|
||||
gem 'pry-byebug', '~> 3.4', platform: :ruby
|
||||
gem 'pry', '>= 0.10'
|
||||
gem 'byebug', '~> 8.2' if RUBY_VERSION < '2.2'
|
||||
gem 'pry-byebug', platform: :ruby
|
||||
end
|
||||
|
||||
group :development, :test do
|
||||
|
||||
@ -49,8 +49,6 @@ Check how to change the adapter in the sections below.
|
||||
`0.10.x` is based on the `0.8.0` code, but with a more flexible
|
||||
architecture. We'd love your help. [Learn how you can help here.](CONTRIBUTING.md)
|
||||
|
||||
It is generally safe and recommended to use the master branch.
|
||||
|
||||
## Installation
|
||||
|
||||
Add this line to your application's Gemfile:
|
||||
@ -187,7 +185,7 @@ and, if there is no serializer, primitives.
|
||||
|
||||
### ActiveModelSerializers::Adapter::Base
|
||||
|
||||
The **`ActiveModelSerializeres::Adapter::Base`** describes the structure of the JSON document generated from a
|
||||
The **`ActiveModelSerializers::Adapter::Base`** describes the structure of the JSON document generated from a
|
||||
serializer. For example, the `Attributes` example represents each serializer as its
|
||||
unmodified attributes. The `JsonApi` adapter represents the serializer as a [JSON
|
||||
API](http://jsonapi.org/) document.
|
||||
|
||||
@ -42,7 +42,7 @@ Gem::Specification.new do |spec|
|
||||
# 'minitest'
|
||||
# 'thread_safe'
|
||||
|
||||
spec.add_runtime_dependency 'jsonapi-renderer', ['>= 0.1.1.beta1', '< 0.2']
|
||||
spec.add_runtime_dependency 'jsonapi-renderer', ['>= 0.1.1.beta1', '< 0.3']
|
||||
spec.add_runtime_dependency 'case_transform', '>= 0.2'
|
||||
|
||||
spec.add_development_dependency 'activerecord', rails_versions
|
||||
|
||||
10
appveyor.yml
10
appveyor.yml
@ -5,19 +5,17 @@ skip_tags: true
|
||||
environment:
|
||||
JRUBY_OPTS: "--dev -J-Xmx1024M --debug"
|
||||
matrix:
|
||||
- ruby_version: "Ruby21"
|
||||
- ruby_version: "Ruby21-x64"
|
||||
- ruby_version: "Ruby23"
|
||||
- ruby_version: "Ruby23-x64"
|
||||
|
||||
cache:
|
||||
- vendor/bundle
|
||||
|
||||
install:
|
||||
- SET PATH=C:\%ruby_version%\bin;%PATH%
|
||||
- gem update --system
|
||||
- gem uninstall bundler -a -x
|
||||
- gem install bundler -v 1.13.7
|
||||
- bundle env
|
||||
- bundle install --path=vendor/bundle --retry=3 --jobs=3
|
||||
- bundle check || bundle install --path=vendor/bundle --retry=3 --jobs=3
|
||||
- bundle clean --force
|
||||
|
||||
before_test:
|
||||
- ruby -v
|
||||
|
||||
@ -36,6 +36,12 @@ The `Attributes` adapter does not include a root key. It is just the serialized
|
||||
|
||||
Use either the `JSON` or `JSON API` adapters if you want the response document to have a root key.
|
||||
|
||||
***IMPORTANT***: Adapter configuration has *no effect* on a serializer instance
|
||||
being used directly. That is, `UserSerializer.new(user).as_json` will *always*
|
||||
behave as if the adapter were the 'Attributes' adapter. See [Outside Controller
|
||||
Usage](../howto/outside_controller_use.md) for more details on recommended
|
||||
usage.
|
||||
|
||||
## Built in Adapters
|
||||
|
||||
### Attributes - Default
|
||||
|
||||
@ -57,6 +57,7 @@ still prefer the render option `:key_transform` over this setting.
|
||||
application, setting `config.key_transform` to `:unaltered` will provide a performance boost.*
|
||||
|
||||
##### default_includes
|
||||
|
||||
What relationships to serialize by default. Default: `'*'`, which includes one level of related
|
||||
objects. See [includes](adapters.md#included) for more info.
|
||||
|
||||
@ -162,6 +163,21 @@ Default: `{}`.
|
||||
|
||||
*Used when `jsonapi_include_toplevel_object` is `true`*
|
||||
|
||||
##### jsonapi_use_foreign_key_on_belongs_to_relationship
|
||||
|
||||
When true, the relationship will determine its resource object identifier
|
||||
without calling the association or its serializer. This can be useful when calling
|
||||
the association object is triggering unnecessary queries.
|
||||
|
||||
For example, if a `comment` belongs to a `post`, and the comment
|
||||
uses the foreign key `post_id`, we can determine the resource object
|
||||
identifier `id` as `comment.post_id` and the `type` from the association options.
|
||||
Or quite simply, it behaves as `belongs_to :post, type: :posts, foreign_key: :post_id`.
|
||||
|
||||
Note: This option has *no effect* on polymorphic associations as we cannot reliably
|
||||
determine the associated object's type without instantiating it.
|
||||
|
||||
Default: `false`.
|
||||
|
||||
## Hooks
|
||||
|
||||
|
||||
@ -290,4 +290,4 @@ See [Usage outside of a controller](../howto/outside_controller_use.md#serializi
|
||||
|
||||
## Pagination
|
||||
|
||||
See [How to add pagination links](https://github.com/rails-api/active_model_serializers/blob/master/docs/howto/add_pagination_links.md).
|
||||
See [How to add pagination links](../howto/add_pagination_links.md).
|
||||
|
||||
@ -294,6 +294,8 @@ end
|
||||
Whether you write the method as above or as `object.comments.where(created_by: scope)`
|
||||
is a matter of preference (assuming `scope_name` has been set).
|
||||
|
||||
Keep in mind that the scope can be set to any available controller reference. This can be utilized to provide access to any other data scopes or presentation helpers.
|
||||
|
||||
##### Controller Authorization Context
|
||||
|
||||
In the controller, the scope/scope_name options are equal to
|
||||
@ -311,7 +313,7 @@ current authorization scope when you call `render :json`.
|
||||
called on every request. This was [also a problem](https://github.com/rails-api/active_model_serializers/pull/1252#issuecomment-159810477)
|
||||
in [`0.9`](https://github.com/rails-api/active_model_serializers/tree/0-9-stable#customizing-scope).
|
||||
|
||||
We can change the scope from `current_user` to `view_context`.
|
||||
We can change the scope from `current_user` to `view_context`, which is included in subclasses of `ActionController::Base`.
|
||||
|
||||
```diff
|
||||
class SomeController < ActionController::Base
|
||||
@ -379,6 +381,7 @@ class PostsController < ActionController::Base
|
||||
end
|
||||
end
|
||||
```
|
||||
Note that any controller reference which provides the desired scope is acceptable, such as another controller method for loading a different resource or reference to helpers. For example, `ActionController::API` does not include `ActionView::ViewContext`, and would need a different reference for passing any helpers into a serializer via `serialization_scope`.
|
||||
|
||||
#### #read_attribute_for_serialization(key)
|
||||
|
||||
|
||||
@ -18,6 +18,13 @@ In order to add the root key you need to use the ```JSON``` Adapter, you can cha
|
||||
ActiveModelSerializers.config.adapter = :json
|
||||
```
|
||||
|
||||
Note that adapter configuration has no effect on a serializer that is called
|
||||
directly, e.g. in a serializer unit test. Instead, something like
|
||||
`UserSerializer.new(user).as_json` will *always* behave as if the adapter were
|
||||
the 'Attributes' adapter. See [Outside Controller
|
||||
Usage](../howto/outside_controller_use.md) for more details on recommended
|
||||
usage.
|
||||
|
||||
You can also specify a class as adapter, as long as it complies with the ActiveModelSerializers adapters interface.
|
||||
It will add the root key to all your serialized endpoints.
|
||||
|
||||
|
||||
@ -142,6 +142,7 @@ module ActiveModel
|
||||
# Make JSON API top-level jsonapi member opt-in
|
||||
# ref: http://jsonapi.org/format/#document-top-level
|
||||
config.jsonapi_include_toplevel_object = false
|
||||
config.jsonapi_use_foreign_key_on_belongs_to_relationship = false
|
||||
config.include_data_default = true
|
||||
|
||||
# For configuring how serializers are found.
|
||||
@ -337,7 +338,7 @@ module ActiveModel
|
||||
# @return [Enumerator<Association>]
|
||||
def associations(include_directive = ActiveModelSerializers.default_include_directive, include_slice = nil)
|
||||
include_slice ||= include_directive
|
||||
return Enumerator.new unless object
|
||||
return Enumerator.new {} unless object
|
||||
|
||||
Enumerator.new do |y|
|
||||
self.class._reflections.each do |key, reflection|
|
||||
|
||||
@ -46,7 +46,10 @@ module ActiveModel
|
||||
# 3. get from collection name, if a named collection
|
||||
key ||= object.respond_to?(:name) ? object.name && object.name.underscore : nil
|
||||
# 4. key may be nil for empty collection and no serializer option
|
||||
key && key.pluralize
|
||||
key &&= key.pluralize
|
||||
# 5. fail if the key cannot be determined
|
||||
key || fail(ArgumentError, 'Cannot infer root key from collection type. Please
|
||||
specify the root or each_serializer option, or render a JSON String')
|
||||
end
|
||||
# rubocop:enable Metrics/CyclomaticComplexity
|
||||
|
||||
|
||||
@ -140,7 +140,7 @@ module ActiveModel
|
||||
def include_data?(include_slice)
|
||||
include_data_setting = options[:include_data_setting]
|
||||
case include_data_setting
|
||||
when :if_sideloaded then include_slice.key?(name)
|
||||
when :if_sideloaded then include_slice.key?(options.fetch(:key, name))
|
||||
when true then true
|
||||
when false then false
|
||||
else fail ArgumentError, "Unknown include_data_setting '#{include_data_setting.inspect}'"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
VERSION = '0.10.6'.freeze
|
||||
VERSION = '0.10.7'.freeze
|
||||
end
|
||||
end
|
||||
|
||||
@ -49,5 +49,5 @@ module ActiveModelSerializers
|
||||
require 'active_model/serializer/version'
|
||||
require 'active_model/serializer'
|
||||
require 'active_model/serializable_resource'
|
||||
require 'active_model_serializers/railtie' if defined?(::Rails)
|
||||
require 'active_model_serializers/railtie' if defined?(::Rails::Railtie)
|
||||
end
|
||||
|
||||
@ -189,7 +189,7 @@ module ActiveModelSerializers
|
||||
|
||||
polymorphic = (options[:polymorphic] || []).include?(assoc_name.to_sym)
|
||||
if polymorphic
|
||||
hash["#{prefix_key}_type".to_sym] = assoc_data.present? ? assoc_data['type'] : nil
|
||||
hash["#{prefix_key}_type".to_sym] = assoc_data.present? ? assoc_data['type'].classify : nil
|
||||
end
|
||||
|
||||
hash
|
||||
|
||||
@ -20,12 +20,13 @@ module ActiveModelSerializers
|
||||
end
|
||||
|
||||
def as_json
|
||||
per_page = collection.try(:per_page) || collection.try(:limit_value) || collection.size
|
||||
pages_from.each_with_object({}) do |(key, value), hash|
|
||||
params = query_parameters.merge(page: { number: value, size: per_page }).to_query
|
||||
|
||||
hash[key] = "#{url(adapter_options)}?#{params}"
|
||||
end
|
||||
{
|
||||
self: location_url,
|
||||
first: first_page_url,
|
||||
prev: prev_page_url,
|
||||
next: next_page_url,
|
||||
last: last_page_url
|
||||
}
|
||||
end
|
||||
|
||||
protected
|
||||
@ -34,25 +35,39 @@ module ActiveModelSerializers
|
||||
|
||||
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
|
||||
def location_url
|
||||
url_for_page(collection.current_page)
|
||||
end
|
||||
|
||||
unless collection.current_page == collection.total_pages
|
||||
pages[:next] = collection.current_page + FIRST_PAGE
|
||||
pages[:last] = collection.total_pages
|
||||
def first_page_url
|
||||
url_for_page(1)
|
||||
end
|
||||
|
||||
def last_page_url
|
||||
if collection.total_pages == 0
|
||||
url_for_page(FIRST_PAGE)
|
||||
else
|
||||
url_for_page(collection.total_pages)
|
||||
end
|
||||
end
|
||||
|
||||
def url(options)
|
||||
def prev_page_url
|
||||
return nil if collection.current_page == FIRST_PAGE
|
||||
url_for_page(collection.current_page - FIRST_PAGE)
|
||||
end
|
||||
|
||||
def next_page_url
|
||||
return nil if collection.total_pages == 0 || collection.current_page == collection.total_pages
|
||||
url_for_page(collection.next_page)
|
||||
end
|
||||
|
||||
def url_for_page(number)
|
||||
params = query_parameters.dup
|
||||
params[:page] = { size: per_page, number: number }
|
||||
"#{url(adapter_options)}?#{params.to_query}"
|
||||
end
|
||||
|
||||
def url(options = {})
|
||||
@url ||= options.fetch(:links, {}).fetch(:self, nil) || request_url
|
||||
end
|
||||
|
||||
@ -63,6 +78,10 @@ module ActiveModelSerializers
|
||||
def query_parameters
|
||||
@query_parameters ||= context.query_parameters
|
||||
end
|
||||
|
||||
def per_page
|
||||
@per_page ||= collection.try(:per_page) || collection.try(:limit_value) || collection.size
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -43,10 +43,16 @@ module ActiveModelSerializers
|
||||
end
|
||||
|
||||
def data_for_one(association)
|
||||
if association.belongs_to? &&
|
||||
parent_serializer.object.respond_to?(association.reflection.foreign_key)
|
||||
id = parent_serializer.object.send(association.reflection.foreign_key)
|
||||
type = association.reflection.type.to_s
|
||||
if belongs_to_id_on_self?(association)
|
||||
id = parent_serializer.read_attribute_for_serialization(association.reflection.foreign_key)
|
||||
type =
|
||||
if association.polymorphic?
|
||||
# We can't infer resource type for polymorphic relationships from the serializer.
|
||||
# We can ONLY know a polymorphic resource type by inspecting each resource.
|
||||
association.lazy_association.serializer.json_key
|
||||
else
|
||||
association.reflection.type.to_s
|
||||
end
|
||||
ResourceIdentifier.for_type_with_id(type, id, serializable_resource_options)
|
||||
else
|
||||
# TODO(BF): Process relationship without evaluating lazy_association
|
||||
@ -86,6 +92,12 @@ module ActiveModelSerializers
|
||||
meta = association.meta
|
||||
meta.respond_to?(:call) ? parent_serializer.instance_eval(&meta) : meta
|
||||
end
|
||||
|
||||
def belongs_to_id_on_self?(association)
|
||||
parent_serializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship &&
|
||||
association.belongs_to? &&
|
||||
parent_serializer.object.respond_to?(association.reflection.foreign_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -2,32 +2,34 @@ module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class ResourceIdentifier
|
||||
def self.type_for(class_name, serializer_type = nil, transform_options = {})
|
||||
if serializer_type
|
||||
raw_type = serializer_type
|
||||
else
|
||||
inflection =
|
||||
if ActiveModelSerializers.config.jsonapi_resource_type == :singular
|
||||
:singularize
|
||||
else
|
||||
:pluralize
|
||||
end
|
||||
|
||||
raw_type = class_name.underscore
|
||||
raw_type = ActiveSupport::Inflector.public_send(inflection, raw_type)
|
||||
raw_type
|
||||
.gsub!('/'.freeze, ActiveModelSerializers.config.jsonapi_namespace_separator)
|
||||
raw_type
|
||||
end
|
||||
def self.type_for(serializer, serializer_type = nil, transform_options = {})
|
||||
raw_type = serializer_type ? serializer_type : raw_type_from_serializer_object(serializer.object)
|
||||
JsonApi.send(:transform_key_casing!, raw_type, transform_options)
|
||||
end
|
||||
|
||||
def self.for_type_with_id(type, id, options)
|
||||
return nil if id.blank?
|
||||
{
|
||||
id: id.to_s,
|
||||
type: type_for(:no_class_needed, type, options)
|
||||
}
|
||||
type = inflect_type(type)
|
||||
type = type_for(:no_class_needed, type, options)
|
||||
if id.blank?
|
||||
{ type: type }
|
||||
else
|
||||
{ id: id.to_s, type: type }
|
||||
end
|
||||
end
|
||||
|
||||
def self.raw_type_from_serializer_object(object)
|
||||
class_name = object.class.name # should use model_name
|
||||
raw_type = class_name.underscore
|
||||
raw_type = inflect_type(raw_type)
|
||||
raw_type
|
||||
.gsub!('/'.freeze, ActiveModelSerializers.config.jsonapi_namespace_separator)
|
||||
raw_type
|
||||
end
|
||||
|
||||
def self.inflect_type(type)
|
||||
singularize = ActiveModelSerializers.config.jsonapi_resource_type == :singular
|
||||
inflection = singularize ? :singularize : :pluralize
|
||||
ActiveSupport::Inflector.public_send(inflection, type)
|
||||
end
|
||||
|
||||
# {http://jsonapi.org/format/#document-resource-identifier-objects Resource Identifier Objects}
|
||||
@ -37,8 +39,11 @@ module ActiveModelSerializers
|
||||
end
|
||||
|
||||
def as_json
|
||||
return nil if id.blank?
|
||||
{ id: id, type: type }
|
||||
if id.blank?
|
||||
{ type: type }
|
||||
else
|
||||
{ id: id.to_s, type: type }
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
@ -48,7 +53,8 @@ module ActiveModelSerializers
|
||||
private
|
||||
|
||||
def type_for(serializer, transform_options)
|
||||
self.class.type_for(serializer.object.class.name, serializer._type, transform_options)
|
||||
serializer_type = serializer._type
|
||||
self.class.type_for(serializer, serializer_type, transform_options)
|
||||
end
|
||||
|
||||
def id_for(serializer)
|
||||
|
||||
@ -45,7 +45,7 @@ module ActionController
|
||||
response = JSON.parse(@response.body)
|
||||
expected = {
|
||||
'restriction_for_id' => '67',
|
||||
'restriction_for_type' => 'discounts',
|
||||
'restriction_for_type' => 'Discount',
|
||||
'restricted_to_id' => nil,
|
||||
'restricted_to_type' => nil
|
||||
}
|
||||
|
||||
@ -58,8 +58,10 @@ module ActionController
|
||||
assert_equal expected_links, response['links']
|
||||
end
|
||||
|
||||
def test_render_only_last_and_next_pagination_links
|
||||
def test_render_only_first_last_and_next_pagination_links
|
||||
expected_links = { 'self' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
|
||||
'first' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
|
||||
'prev' => nil,
|
||||
'next' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2",
|
||||
'last' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2" }
|
||||
get :render_pagination_using_will_paginate, params: { page: { number: 1, size: 2 } }
|
||||
@ -78,17 +80,21 @@ module ActionController
|
||||
assert_equal expected_links, response['links']
|
||||
end
|
||||
|
||||
def test_render_only_prev_and_first_pagination_links
|
||||
def test_render_only_prev_first_and_last_pagination_links
|
||||
expected_links = { 'self' => "#{KAMINARI_URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1",
|
||||
'first' => "#{KAMINARI_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=1",
|
||||
'prev' => "#{KAMINARI_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=1" }
|
||||
'prev' => "#{KAMINARI_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=1",
|
||||
'next' => nil,
|
||||
'last' => "#{KAMINARI_URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1" }
|
||||
get :render_pagination_using_kaminari, params: { page: { number: 3, size: 1 } }
|
||||
response = JSON.parse(@response.body)
|
||||
assert_equal expected_links, response['links']
|
||||
end
|
||||
|
||||
def test_render_only_last_and_next_pagination_links_with_additional_params
|
||||
def test_render_only_first_last_and_next_pagination_links_with_additional_params
|
||||
expected_links = { 'self' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2&teste=additional",
|
||||
'first' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2&teste=additional",
|
||||
'prev' => nil,
|
||||
'next' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2&teste=additional",
|
||||
'last' => "#{WILL_PAGINATE_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2&teste=additional" }
|
||||
get :render_pagination_using_will_paginate, params: { page: { number: 1, size: 2 }, teste: 'additional' }
|
||||
@ -96,10 +102,12 @@ module ActionController
|
||||
assert_equal expected_links, response['links']
|
||||
end
|
||||
|
||||
def test_render_only_prev_and_first_pagination_links_with_additional_params
|
||||
def test_render_only_prev_first_and_last_pagination_links_with_additional_params
|
||||
expected_links = { 'self' => "#{KAMINARI_URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1&teste=additional",
|
||||
'first' => "#{KAMINARI_URI}?page%5Bnumber%5D=1&page%5Bsize%5D=1&teste=additional",
|
||||
'prev' => "#{KAMINARI_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=1&teste=additional" }
|
||||
'prev' => "#{KAMINARI_URI}?page%5Bnumber%5D=2&page%5Bsize%5D=1&teste=additional",
|
||||
'next' => nil,
|
||||
'last' => "#{KAMINARI_URI}?page%5Bnumber%5D=3&page%5Bsize%5D=1&teste=additional" }
|
||||
get :render_pagination_using_kaminari, params: { page: { number: 3, size: 1 }, teste: 'additional' }
|
||||
response = JSON.parse(@response.body)
|
||||
assert_equal expected_links, response['links']
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
require 'test_helper'
|
||||
|
||||
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 = ActiveModelSerializers::Adapter::JsonApi.new(@serializer)
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
def test_no_includes_linked_comments
|
||||
assert_nil @adapter.serializable_hash[:linked]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -6,7 +6,7 @@ module ActiveModel
|
||||
class JsonApi
|
||||
class IncludeParamTest < ActiveSupport::TestCase
|
||||
IncludeParamAuthor = Class.new(::Model) do
|
||||
associations :tags, :posts
|
||||
associations :tags, :posts, :roles
|
||||
end
|
||||
|
||||
class CustomCommentLoader
|
||||
@ -51,14 +51,19 @@ module ActiveModel
|
||||
include_data :if_sideloaded
|
||||
IncludeParamAuthorSerializer.comment_loader.all
|
||||
end
|
||||
has_many :roles, key: :granted_roles do
|
||||
include_data :if_sideloaded
|
||||
end
|
||||
end
|
||||
|
||||
def setup
|
||||
IncludeParamAuthorSerializer.comment_loader = Class.new(CustomCommentLoader).new
|
||||
@tag = Tag.new(id: 1337, name: 'mytag')
|
||||
@role = Role.new(id: 1337, name: 'myrole')
|
||||
@author = IncludeParamAuthor.new(
|
||||
id: 1337,
|
||||
tags: [@tag]
|
||||
tags: [@tag],
|
||||
roles: [@role]
|
||||
)
|
||||
end
|
||||
|
||||
@ -105,6 +110,31 @@ module ActiveModel
|
||||
assert_equal(expected, hash[:included])
|
||||
end
|
||||
|
||||
def test_sideloads_included_when_using_key
|
||||
expected = [
|
||||
{
|
||||
id: '1337',
|
||||
type: 'roles',
|
||||
attributes: {
|
||||
name: 'myrole',
|
||||
description: nil,
|
||||
slug: 'myrole-1337'
|
||||
},
|
||||
relationships: {
|
||||
author: { data: nil }
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
hash = result(include: :granted_roles)
|
||||
assert_equal(expected, hash[:included])
|
||||
end
|
||||
|
||||
def test_sideloads_not_included_when_using_name_when_key_defined
|
||||
hash = result(include: :roles)
|
||||
assert_nil(hash[:included])
|
||||
end
|
||||
|
||||
def test_nested_relationship
|
||||
expected = {
|
||||
data: [
|
||||
|
||||
@ -54,6 +54,16 @@ module ActiveModelSerializers
|
||||
}
|
||||
end
|
||||
|
||||
def empty_collection_links
|
||||
{
|
||||
self: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
|
||||
first: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
|
||||
prev: nil,
|
||||
next: nil,
|
||||
last: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2"
|
||||
}
|
||||
end
|
||||
|
||||
def links
|
||||
{
|
||||
links: {
|
||||
@ -71,7 +81,9 @@ module ActiveModelSerializers
|
||||
links: {
|
||||
self: "#{URI}?page%5Bnumber%5D=3&page%5Bsize%5D=2",
|
||||
first: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
|
||||
prev: "#{URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2"
|
||||
prev: "#{URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2",
|
||||
next: nil,
|
||||
last: "#{URI}?page%5Bnumber%5D=3&page%5Bsize%5D=2"
|
||||
}
|
||||
}
|
||||
end
|
||||
@ -108,10 +120,10 @@ module ActiveModelSerializers
|
||||
end
|
||||
end
|
||||
|
||||
def expected_response_with_no_data_pagination_links
|
||||
def expected_response_with_empty_collection_pagination_links
|
||||
{}.tap do |hash|
|
||||
hash[:data] = []
|
||||
hash[:links] = {}
|
||||
hash.merge! links: empty_collection_links
|
||||
end
|
||||
end
|
||||
|
||||
@ -139,7 +151,7 @@ module ActiveModelSerializers
|
||||
|
||||
adapter = load_adapter(using_kaminari(1), mock_request)
|
||||
|
||||
assert_equal expected_response_with_no_data_pagination_links, adapter.serializable_hash
|
||||
assert_equal expected_response_with_empty_collection_pagination_links, adapter.serializable_hash
|
||||
end
|
||||
|
||||
def test_pagination_links_when_zero_results_will_paginate
|
||||
@ -147,7 +159,7 @@ module ActiveModelSerializers
|
||||
|
||||
adapter = load_adapter(using_will_paginate(1), mock_request)
|
||||
|
||||
assert_equal expected_response_with_no_data_pagination_links, adapter.serializable_hash
|
||||
assert_equal expected_response_with_empty_collection_pagination_links, adapter.serializable_hash
|
||||
end
|
||||
|
||||
def test_last_page_pagination_links_using_kaminari
|
||||
@ -171,10 +183,11 @@ module ActiveModelSerializers
|
||||
def test_raises_descriptive_error_when_serialization_context_unset
|
||||
render_options = { adapter: :json_api }
|
||||
adapter = serializable(using_kaminari, render_options)
|
||||
exception = assert_raises do
|
||||
exception_class = ActiveModelSerializers::Adapter::JsonApi::PaginationLinks::MissingSerializationContextError
|
||||
|
||||
exception = assert_raises(exception_class) do
|
||||
adapter.as_json
|
||||
end
|
||||
exception_class = ActiveModelSerializers::Adapter::JsonApi::PaginationLinks::MissingSerializationContextError
|
||||
assert_equal exception_class, exception.class
|
||||
assert_match(/CollectionSerializer#paginated\?/, exception.message)
|
||||
end
|
||||
|
||||
@ -125,7 +125,7 @@ module ActiveModelSerializers
|
||||
src: 'http://example.com/images/productivity.png',
|
||||
author_id: nil,
|
||||
photographer_id: '9',
|
||||
photographer_type: 'people',
|
||||
photographer_type: 'Person',
|
||||
comment_ids: %w(1 2)
|
||||
}
|
||||
assert_equal(expected, parsed_hash)
|
||||
|
||||
@ -1,110 +0,0 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class ResourceIdentifierTest < ActiveSupport::TestCase
|
||||
class WithDefinedTypeSerializer < ActiveModel::Serializer
|
||||
type 'with_defined_type'
|
||||
end
|
||||
|
||||
class WithDefinedIdSerializer < ActiveModel::Serializer
|
||||
def id
|
||||
'special_id'
|
||||
end
|
||||
end
|
||||
|
||||
class FragmentedSerializer < ActiveModel::Serializer
|
||||
cache only: :id
|
||||
|
||||
def id
|
||||
'special_id'
|
||||
end
|
||||
end
|
||||
|
||||
setup do
|
||||
@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_type_with_namespace
|
||||
Object.const_set(:Admin, Module.new)
|
||||
model = Class.new(::Model)
|
||||
Admin.const_set(:PowerUser, model)
|
||||
serializer = Class.new(ActiveModel::Serializer)
|
||||
Admin.const_set(:PowerUserSerializer, serializer)
|
||||
with_namespace_separator '--' do
|
||||
admin_user = Admin::PowerUser.new
|
||||
serializer = Admin::PowerUserSerializer.new(admin_user)
|
||||
expected = {
|
||||
id: admin_user.id,
|
||||
type: 'admin--power-users'
|
||||
}
|
||||
|
||||
identifier = ResourceIdentifier.new(serializer, {})
|
||||
actual = identifier.as_json
|
||||
assert_equal(expected, actual)
|
||||
end
|
||||
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
|
||||
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)
|
||||
ensure
|
||||
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, nil)
|
||||
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, nil)
|
||||
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
|
||||
@ -1,7 +1,6 @@
|
||||
require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module ActiveModelSerializers
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class TypeTest < ActiveSupport::TestCase
|
||||
@ -20,13 +19,13 @@ module ActiveModel
|
||||
end
|
||||
|
||||
def test_config_plural
|
||||
with_jsonapi_resource_type :plural do
|
||||
with_jsonapi_inflection :plural do
|
||||
assert_type(@author, 'authors')
|
||||
end
|
||||
end
|
||||
|
||||
def test_config_singular
|
||||
with_jsonapi_resource_type :singular do
|
||||
with_jsonapi_inflection :singular do
|
||||
assert_type(@author, 'author')
|
||||
end
|
||||
end
|
||||
@ -46,14 +45,147 @@ module ActiveModel
|
||||
hash = serializable(resource, opts).serializable_hash
|
||||
assert_equal(expected_type, hash.fetch(:data).fetch(:type))
|
||||
end
|
||||
end
|
||||
class ResourceIdentifierTest < ActiveSupport::TestCase
|
||||
class WithDefinedTypeSerializer < ActiveModel::Serializer
|
||||
type 'with_defined_types'
|
||||
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
|
||||
class WithDefinedIdSerializer < ActiveModel::Serializer
|
||||
def id
|
||||
'special_id'
|
||||
end
|
||||
end
|
||||
|
||||
class FragmentedSerializer < ActiveModel::Serializer
|
||||
cache only: :id
|
||||
|
||||
def id
|
||||
'special_id'
|
||||
end
|
||||
end
|
||||
|
||||
setup do
|
||||
@model = Author.new(id: 1, name: 'Steve K.')
|
||||
ActionController::Base.cache_store.clear
|
||||
end
|
||||
|
||||
def test_defined_type
|
||||
actual = with_jsonapi_inflection :plural do
|
||||
actual_resource_identifier_object(WithDefinedTypeSerializer, @model)
|
||||
end
|
||||
expected = { id: expected_model_id(@model), type: 'with-defined-types' }
|
||||
assert_equal actual, expected
|
||||
end
|
||||
|
||||
def test_defined_type_not_inflected
|
||||
actual = with_jsonapi_inflection :singular do
|
||||
actual_resource_identifier_object(WithDefinedTypeSerializer, @model)
|
||||
end
|
||||
expected = { id: expected_model_id(@model), type: 'with-defined-types' }
|
||||
assert_equal actual, expected
|
||||
end
|
||||
|
||||
def test_singular_type
|
||||
actual = with_jsonapi_inflection :singular do
|
||||
actual_resource_identifier_object(AuthorSerializer, @model)
|
||||
end
|
||||
expected = { id: expected_model_id(@model), type: 'author' }
|
||||
assert_equal actual, expected
|
||||
end
|
||||
|
||||
def test_plural_type
|
||||
actual = with_jsonapi_inflection :plural do
|
||||
actual_resource_identifier_object(AuthorSerializer, @model)
|
||||
end
|
||||
expected = { id: expected_model_id(@model), type: 'authors' }
|
||||
assert_equal actual, expected
|
||||
end
|
||||
|
||||
def test_type_with_namespace
|
||||
Object.const_set(:Admin, Module.new)
|
||||
model = Class.new(::Model)
|
||||
Admin.const_set(:PowerUser, model)
|
||||
serializer = Class.new(ActiveModel::Serializer)
|
||||
Admin.const_set(:PowerUserSerializer, serializer)
|
||||
with_namespace_separator '--' do
|
||||
admin_user = Admin::PowerUser.new
|
||||
serializer = Admin::PowerUserSerializer.new(admin_user)
|
||||
expected = {
|
||||
id: admin_user.id,
|
||||
type: 'admin--power-users'
|
||||
}
|
||||
|
||||
identifier = ResourceIdentifier.new(serializer, {})
|
||||
actual = identifier.as_json
|
||||
assert_equal(expected, actual)
|
||||
end
|
||||
end
|
||||
|
||||
def test_id_defined_on_object
|
||||
actual = actual_resource_identifier_object(AuthorSerializer, @model)
|
||||
expected = { id: @model.id.to_s, type: expected_model_type(@model) }
|
||||
assert_equal actual, expected
|
||||
end
|
||||
|
||||
def test_blank_id
|
||||
model = Author.new(id: nil, name: 'Steve K.')
|
||||
actual = actual_resource_identifier_object(AuthorSerializer, model)
|
||||
expected = { type: expected_model_type(model) }
|
||||
assert_equal actual, expected
|
||||
end
|
||||
|
||||
def test_for_type_with_id
|
||||
id = 1
|
||||
actual = ResourceIdentifier.for_type_with_id('admin_user', id, {})
|
||||
expected = { id: '1', type: 'admin-users' }
|
||||
assert_equal actual, expected
|
||||
end
|
||||
|
||||
def test_for_type_with_id_given_blank_id
|
||||
id = ''
|
||||
actual = ResourceIdentifier.for_type_with_id('admin_user', id, {})
|
||||
expected = { type: 'admin-users' }
|
||||
assert_equal actual, expected
|
||||
end
|
||||
|
||||
def test_for_type_with_id_inflected
|
||||
id = 2
|
||||
actual = with_jsonapi_inflection :singular do
|
||||
ResourceIdentifier.for_type_with_id('admin_users', id, {})
|
||||
end
|
||||
expected = { id: '2', type: 'admin-user' }
|
||||
assert_equal actual, expected
|
||||
end
|
||||
|
||||
def test_id_defined_on_serializer
|
||||
actual = actual_resource_identifier_object(WithDefinedIdSerializer, @model)
|
||||
expected = { id: 'special_id', type: expected_model_type(@model) }
|
||||
assert_equal actual, expected
|
||||
end
|
||||
|
||||
def test_id_defined_on_fragmented
|
||||
actual = actual_resource_identifier_object(FragmentedSerializer, @model)
|
||||
expected = { id: 'special_id', type: expected_model_type(@model) }
|
||||
assert_equal actual, expected
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def actual_resource_identifier_object(serializer_class, model)
|
||||
serializer = serializer_class.new(model)
|
||||
resource_identifier = ResourceIdentifier.new(serializer, nil)
|
||||
resource_identifier.as_json
|
||||
end
|
||||
|
||||
def expected_model_type(model, inflection = ActiveModelSerializers.config.jsonapi_resource_type)
|
||||
with_jsonapi_inflection inflection do
|
||||
model.class.model_name.send(inflection)
|
||||
end
|
||||
end
|
||||
|
||||
def expected_model_id(model)
|
||||
model.id.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -165,6 +165,53 @@ module ActiveModel
|
||||
|
||||
assert_equal(expected, serialization(@picture, :json_api))
|
||||
end
|
||||
|
||||
def test_json_api_serialization_with_polymorphic_belongs_to
|
||||
expected = {
|
||||
data: {
|
||||
id: '1',
|
||||
type: 'poly-tags',
|
||||
attributes: { phrase: 'foo' },
|
||||
relationships: {
|
||||
:"object-tags" => {
|
||||
data: [
|
||||
{ id: '1', type: 'object-tags' },
|
||||
{ id: '5', type: 'object-tags' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
included: [
|
||||
{
|
||||
id: '1',
|
||||
type: 'object-tags',
|
||||
relationships: {
|
||||
taggable: {
|
||||
data: { id: '42', type: 'employees' }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '42',
|
||||
type: 'employees'
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
type: 'object-tags',
|
||||
relationships: {
|
||||
taggable: {
|
||||
data: { id: '1', type: 'pictures' }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
type: 'pictures'
|
||||
}
|
||||
]
|
||||
}
|
||||
assert_equal(expected, tag_serialization(:json_api))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -93,12 +93,16 @@ module ActiveModel
|
||||
resource = []
|
||||
resource.define_singleton_method(:name) { nil }
|
||||
serializer = collection_serializer.new(resource)
|
||||
assert_nil serializer.json_key
|
||||
assert_raise ArgumentError do
|
||||
serializer.json_key
|
||||
end
|
||||
end
|
||||
|
||||
def test_json_key_with_resource_without_name_and_no_serializers
|
||||
serializer = collection_serializer.new([])
|
||||
assert_nil serializer.json_key
|
||||
assert_raise ArgumentError do
|
||||
serializer.json_key
|
||||
end
|
||||
end
|
||||
|
||||
def test_json_key_with_empty_resources_with_serializer
|
||||
|
||||
4
test/fixtures/active_record.rb
vendored
4
test/fixtures/active_record.rb
vendored
@ -89,7 +89,7 @@ class ObjectTag < ActiveRecord::Base
|
||||
end
|
||||
class PolymorphicObjectTagSerializer < ActiveModel::Serializer
|
||||
attributes :id
|
||||
has_many :taggable, serializer: PolymorphicSimpleSerializer, polymorphic: true
|
||||
belongs_to :taggable, serializer: PolymorphicSimpleSerializer, polymorphic: true
|
||||
end
|
||||
|
||||
class PolyTag < ActiveRecord::Base
|
||||
@ -109,5 +109,5 @@ class PolymorphicHasManySerializer < ActiveModel::Serializer
|
||||
end
|
||||
class PolymorphicBelongsToSerializer < ActiveModel::Serializer
|
||||
attributes :id, :title
|
||||
has_one :imageable, serializer: PolymorphicHasManySerializer, polymorphic: true
|
||||
belongs_to :imageable, serializer: PolymorphicHasManySerializer, polymorphic: true
|
||||
end
|
||||
|
||||
@ -159,12 +159,56 @@ module ActiveModel
|
||||
end
|
||||
end
|
||||
|
||||
actual = serializable(post, adapter: :json_api, serializer: BelongsToBlogModelSerializer).as_json
|
||||
actual =
|
||||
begin
|
||||
original_option = BelongsToBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship
|
||||
BelongsToBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship = true
|
||||
serializable(post, adapter: :json_api, serializer: BelongsToBlogModelSerializer).as_json
|
||||
ensure
|
||||
BelongsToBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship = original_option
|
||||
end
|
||||
expected = { data: { id: '1', type: 'posts', relationships: { blog: { data: { id: '5', type: 'blogs' } } } } }
|
||||
|
||||
assert_equal expected, actual
|
||||
end
|
||||
|
||||
class ExternalBlog < Blog
|
||||
attributes :external_id
|
||||
end
|
||||
class BelongsToExternalBlogModel < ::Model
|
||||
attributes :id, :title, :external_blog_id
|
||||
associations :external_blog
|
||||
end
|
||||
class BelongsToExternalBlogModelSerializer < ActiveModel::Serializer
|
||||
type :posts
|
||||
belongs_to :external_blog
|
||||
|
||||
def external_blog_id
|
||||
object.external_blog.external_id
|
||||
end
|
||||
end
|
||||
|
||||
def test_belongs_to_allows_id_overwriting
|
||||
attributes = {
|
||||
id: 1,
|
||||
title: 'Title',
|
||||
external_blog: ExternalBlog.new(id: 5, external_id: 6)
|
||||
}
|
||||
post = BelongsToExternalBlogModel.new(attributes)
|
||||
|
||||
actual =
|
||||
begin
|
||||
original_option = BelongsToExternalBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship
|
||||
BelongsToExternalBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship = true
|
||||
serializable(post, adapter: :json_api, serializer: BelongsToExternalBlogModelSerializer).as_json
|
||||
ensure
|
||||
BelongsToExternalBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship = original_option
|
||||
end
|
||||
expected = { data: { id: '1', type: 'posts', relationships: { :'external-blog' => { data: { id: '6', type: 'external-blogs' } } } } }
|
||||
|
||||
assert_equal expected, actual
|
||||
end
|
||||
|
||||
class InlineAssociationTestPostSerializer < ActiveModel::Serializer
|
||||
has_many :comments
|
||||
has_many :comments, key: :last_comments do
|
||||
|
||||
@ -54,7 +54,7 @@ module TestHelpers
|
||||
require 'rails'
|
||||
require 'action_controller/railtie'
|
||||
|
||||
@app = Class.new(Rails::Application) do
|
||||
app = Class.new(Rails::Application) do
|
||||
config.eager_load = false
|
||||
config.session_store :cookie_store, key: '_myapp_session'
|
||||
config.active_support.deprecation = :log
|
||||
@ -67,8 +67,10 @@ module TestHelpers
|
||||
config.logger = fake_logger
|
||||
Rails.application.routes.default_url_options = { host: 'example.com' }
|
||||
end
|
||||
@app.respond_to?(:secrets) && @app.secrets.secret_key_base = '3b7cd727ee24e8444053437c36cc66c4'
|
||||
def app.name; 'IsolatedRailsApp'; end # rubocop:disable Style/SingleLineMethods
|
||||
app.respond_to?(:secrets) && app.secrets.secret_key_base = '3b7cd727ee24e8444053437c36cc66c4'
|
||||
|
||||
@app = app
|
||||
yield @app if block_given?
|
||||
@app.initialize!
|
||||
end
|
||||
|
||||
@ -47,6 +47,14 @@ module SerializationTesting
|
||||
ActiveModelSerializers.config.replace(old_config)
|
||||
end
|
||||
|
||||
def with_jsonapi_inflection(inflection)
|
||||
original_inflection = ActiveModelSerializers.config.jsonapi_resource_type
|
||||
ActiveModelSerializers.config.jsonapi_resource_type = inflection
|
||||
yield
|
||||
ensure
|
||||
ActiveModelSerializers.config.jsonapi_resource_type = original_inflection
|
||||
end
|
||||
|
||||
def with_serializer_lookup_disabled
|
||||
original_serializer_lookup = ActiveModelSerializers.config.serializer_lookup_enabled
|
||||
ActiveModelSerializers.config.serializer_lookup_enabled = false
|
||||
|
||||
Loading…
Reference in New Issue
Block a user