mirror of
https://github.com/ditkrg/active_model_serializers.git
synced 2026-01-23 06:16:50 +00:00
Compare commits
No commits in common. "master" and "v0.9.7" have entirely different histories.
29
.github/ISSUE_TEMPLATE.md
vendored
29
.github/ISSUE_TEMPLATE.md
vendored
@ -1,29 +0,0 @@
|
|||||||
#### Expected behavior vs actual behavior
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### Steps to reproduce
|
|
||||||
*(e.g., detailed walkthrough, runnable script, example application)*
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### Environment
|
|
||||||
|
|
||||||
ActiveModelSerializers Version *(commit ref if not on tag)*:
|
|
||||||
|
|
||||||
Output of `ruby -e "puts RUBY_DESCRIPTION"`:
|
|
||||||
|
|
||||||
OS Type & Version:
|
|
||||||
|
|
||||||
Integrated application and version *(e.g., Rails, Grape, etc)*:
|
|
||||||
|
|
||||||
|
|
||||||
#### Backtrace
|
|
||||||
*(e.g., provide any applicable backtraces from your application)*
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### Additonal helpful information
|
|
||||||
*(e.g., Gemfile.lock, configurations, PR containing a failing test, git bisect results)*
|
|
||||||
|
|
||||||
|
|
||||||
15
.github/PULL_REQUEST_TEMPLATE.md
vendored
15
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,15 +0,0 @@
|
|||||||
#### Purpose
|
|
||||||
|
|
||||||
|
|
||||||
#### Changes
|
|
||||||
|
|
||||||
|
|
||||||
#### Caveats
|
|
||||||
|
|
||||||
|
|
||||||
#### Related GitHub issues
|
|
||||||
|
|
||||||
|
|
||||||
#### Additional helpful information
|
|
||||||
|
|
||||||
|
|
||||||
17
.gitignore
vendored
17
.gitignore
vendored
@ -3,16 +3,13 @@
|
|||||||
.bundle
|
.bundle
|
||||||
.config
|
.config
|
||||||
.yardoc
|
.yardoc
|
||||||
Gemfile.lock
|
*.lock
|
||||||
Gemfile.local
|
|
||||||
InstalledFiles
|
InstalledFiles
|
||||||
_yardoc
|
_yardoc
|
||||||
coverage
|
coverage
|
||||||
doc/
|
doc/
|
||||||
lib/bundler/man
|
lib/bundler/man
|
||||||
pkg
|
pkg
|
||||||
Vagrantfile
|
|
||||||
.vagrant
|
|
||||||
rdoc
|
rdoc
|
||||||
spec/reports
|
spec/reports
|
||||||
test/tmp
|
test/tmp
|
||||||
@ -20,16 +17,4 @@ test/version_tmp
|
|||||||
tmp
|
tmp
|
||||||
*.swp
|
*.swp
|
||||||
.ruby-version
|
.ruby-version
|
||||||
.ruby-gemset
|
|
||||||
vendor/bundle
|
vendor/bundle
|
||||||
tags
|
|
||||||
|
|
||||||
# silly macs
|
|
||||||
.DS_Store
|
|
||||||
.DS_Store?
|
|
||||||
._*
|
|
||||||
.Spotlight-V100
|
|
||||||
.Trashes
|
|
||||||
Icon?
|
|
||||||
ehthumbs.db
|
|
||||||
Thumbs.db
|
|
||||||
|
|||||||
49
.travis.yml
49
.travis.yml
@ -2,9 +2,54 @@ language: ruby
|
|||||||
|
|
||||||
sudo: false
|
sudo: false
|
||||||
|
|
||||||
|
rvm:
|
||||||
|
- 1.9.3 # EOL
|
||||||
|
- 2.0.0 # EOL
|
||||||
|
- 2.1
|
||||||
|
- ruby-head
|
||||||
|
- jruby-9.1.5.0 # is precompiled per http://rubies.travis-ci.org/
|
||||||
|
|
||||||
|
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:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
- vendor/bundle
|
- vendor/bundle
|
||||||
|
|
||||||
script:
|
env:
|
||||||
- true
|
global:
|
||||||
|
- "JRUBY_OPTS='--dev -J-Xmx1024M --debug'"
|
||||||
|
matrix:
|
||||||
|
- "RAILS_VERSION=4.0"
|
||||||
|
- "RAILS_VERSION=4.1"
|
||||||
|
- "RAILS_VERSION=4.2"
|
||||||
|
- "RAILS_VERSION=5.0"
|
||||||
|
- "RAILS_VERSION=master"
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
exclude:
|
||||||
|
- rvm: 1.9.3
|
||||||
|
env: RAILS_VERSION=master
|
||||||
|
- rvm: 2.0.0
|
||||||
|
env: RAILS_VERSION=master
|
||||||
|
- rvm: 2.1
|
||||||
|
env: RAILS_VERSION=master
|
||||||
|
- rvm: jruby-9.1.5.0
|
||||||
|
env: RAILS_VERSION=master
|
||||||
|
- rvm: 1.9.3
|
||||||
|
env: RAILS_VERSION=5.0
|
||||||
|
- rvm: 2.0.0
|
||||||
|
env: RAILS_VERSION=5.0
|
||||||
|
- rvm: 2.1
|
||||||
|
env: RAILS_VERSION=5.0
|
||||||
|
- rvm: jruby-9.1.5.0
|
||||||
|
env: RAILS_VERSION=5.0
|
||||||
|
allow_failures:
|
||||||
|
- rvm: ruby-head
|
||||||
|
- env: "RAILS_VERSION=master"
|
||||||
|
fast_finish: true
|
||||||
|
|||||||
@ -1,92 +0,0 @@
|
|||||||
## 0.08.x
|
|
||||||
|
|
||||||
### v0.8.3 (2014/12/10 14:45 +00:00)
|
|
||||||
- [#753](https://github.com/rails-api/active_model_serializers/pull/753) Test against Ruby 2.2 on Travis CI (@tricknotes)
|
|
||||||
- [#745](https://github.com/rails-api/active_model_serializers/pull/745) Missing a word (@jockee)
|
|
||||||
|
|
||||||
### v0.8.2 (2014/09/01 21:00 +00:00)
|
|
||||||
- [#612](https://github.com/rails-api/active_model_serializers/pull/612) Feature/adapter (@bolshakov)
|
|
||||||
* adds adapters pattern
|
|
||||||
- [#615](https://github.com/rails-api/active_model_serializers/pull/615) Rails does not support const_defined? in development mode (@tpitale)
|
|
||||||
- [#613](https://github.com/rails-api/active_model_serializers/pull/613) README: typo fix on attributes (@spk)
|
|
||||||
- [#614](https://github.com/rails-api/active_model_serializers/pull/614) Fix rails 4.0.x build. (@arthurnn)
|
|
||||||
- [#610](https://github.com/rails-api/active_model_serializers/pull/610) ArraySerializer (@bolshakov)
|
|
||||||
- [#607](https://github.com/rails-api/active_model_serializers/pull/607) ruby syntax highlights (@zigomir)
|
|
||||||
- [#602](https://github.com/rails-api/active_model_serializers/pull/602) Add DSL for associations (@JordanFaust)
|
|
||||||
|
|
||||||
### 0.8.1 (May 6, 2013)
|
|
||||||
|
|
||||||
* Fix bug whereby a serializer using 'options' would blow up.
|
|
||||||
|
|
||||||
### 0.8.0 (May 5, 2013)
|
|
||||||
|
|
||||||
* Attributes can now have optional types.
|
|
||||||
|
|
||||||
* A new DefaultSerializer ensures that POROs behave the same way as ActiveModels.
|
|
||||||
|
|
||||||
* If you wish to override ActiveRecord::Base#to_Json, you can now require
|
|
||||||
'active_record/serializer_override'. We don't recommend you do this, but
|
|
||||||
many users do, so we've left it optional.
|
|
||||||
|
|
||||||
* Fixed a bug where ActionController wouldn't always have MimeResponds.
|
|
||||||
|
|
||||||
* An optinal caching feature allows you to cache JSON & hashes that AMS uses.
|
|
||||||
Adding 'cached true' to your Serializers will turn on this cache.
|
|
||||||
|
|
||||||
* URL helpers used inside of Engines now work properly.
|
|
||||||
|
|
||||||
* Serializers now can filter attributes with `only` and `except`:
|
|
||||||
|
|
||||||
```
|
|
||||||
UserSerializer.new(user, only: [:first_name, :last_name])
|
|
||||||
UserSerializer.new(user, except: :first_name)
|
|
||||||
```
|
|
||||||
|
|
||||||
* Basic Mongoid support. We now include our mixins in the right place.
|
|
||||||
|
|
||||||
* On Ruby 1.8, we now generate an `id` method that properly serializes `id`
|
|
||||||
columns. See issue #127 for more.
|
|
||||||
|
|
||||||
* Add an alias for `scope` method to be the name of the context. By default
|
|
||||||
this is `current_user`. The name is automatically set when using
|
|
||||||
`serialization_scope` in the controller.
|
|
||||||
|
|
||||||
* Pass through serialization options (such as `:include`) when a model
|
|
||||||
has no serializer defined.
|
|
||||||
|
|
||||||
## [0.7.0 (March 6, 2013)](https://github.com/rails-api/active_model_serializers/commit/fabdc621ff97fbeca317f6301973dd4564b9e695)
|
|
||||||
|
|
||||||
* ```embed_key``` option to allow embedding by attributes other than IDs
|
|
||||||
* Fix rendering nil with custom serializer
|
|
||||||
* Fix global ```self.root = false```
|
|
||||||
* Add support for specifying the serializer for an association as a String
|
|
||||||
* Able to specify keys on the attributes method
|
|
||||||
* Serializer Reloading via ActiveSupport::DescendantsTracker
|
|
||||||
* Reduce double map to once; Fixes datamapper eager loading.
|
|
||||||
|
|
||||||
## 0.6.0 (October 22, 2012)
|
|
||||||
|
|
||||||
* Serialize sets properly
|
|
||||||
* Add root option to ArraySerializer
|
|
||||||
* Support polymorphic associations
|
|
||||||
* Support :each_serializer in ArraySerializer
|
|
||||||
* Add `scope` method to easily access the scope in the serializer
|
|
||||||
* Fix regression with Rails 3.2.6; add Rails 4 support
|
|
||||||
* Allow serialization_scope to be disabled with serialization_scope nil
|
|
||||||
* Array serializer should support pure ruby objects besides serializers
|
|
||||||
|
|
||||||
## 0.05.x
|
|
||||||
|
|
||||||
### [0.5.2 (June 5, 2012)](https://github.com/rails-api/active_model_serializers/commit/615afd125c260432d456dc8be845867cf87ea118#diff-0c5c12f311d3b54734fff06069efd2ac)
|
|
||||||
|
|
||||||
### [0.5.1 (May 23, 2012)](https://github.com/rails-api/active_model_serializers/commit/00194ec0e41831802fcbf893a34c0bb0853ebe14#diff-0c5c12f311d3b54734fff06069efd2ac)
|
|
||||||
|
|
||||||
### [0.5.0 (May 16, 2012)](https://github.com/rails-api/active_model_serializers/commit/33d4842dcd35c7167b0b33fc0abcf00fb2c92286)
|
|
||||||
|
|
||||||
* First tagged version
|
|
||||||
* Changes generators to always generate an ApplicationSerializer
|
|
||||||
|
|
||||||
## [0.1.0 (December 21, 2011)](https://github.com/rails-api/active_model_serializers/commit/1e0c9ef93b96c640381575dcd30be07ac946818b)
|
|
||||||
|
|
||||||
## First Commit as [Rails Serializers 0.0.1](https://github.com/rails-api/active_model_serializers/commit/d72b66d4c5355b0ff0a75a04895fcc4ea5b0c65e)
|
|
||||||
(December 1, 2011).
|
|
||||||
@ -1,74 +0,0 @@
|
|||||||
## 0.09.x
|
|
||||||
|
|
||||||
### v0.9.3 (2015/01/21 20:29 +00:00)
|
|
||||||
|
|
||||||
Features:
|
|
||||||
- [#774](https://github.com/rails-api/active_model_serializers/pull/774) Fix nested include attributes (@nhocki)
|
|
||||||
- [#771](https://github.com/rails-api/active_model_serializers/pull/771) Make linked resource type names consistent with root names (@sweatypitts)
|
|
||||||
- [#696](https://github.com/rails-api/active_model_serializers/pull/696) Explicitly set serializer for associations (@ggordon)
|
|
||||||
- [#700](https://github.com/rails-api/active_model_serializers/pull/700) sparse fieldsets (@arenoir)
|
|
||||||
- [#768](https://github.com/rails-api/active_model_serializers/pull/768) Adds support for `meta` and `meta_key` attribute (@kurko)
|
|
||||||
|
|
||||||
### v0.9.1 (2014/12/04 11:54 +00:00)
|
|
||||||
- [#707](https://github.com/rails-api/active_model_serializers/pull/707) A Friendly Note on Which AMS Version to Use (@jherdman)
|
|
||||||
- [#730](https://github.com/rails-api/active_model_serializers/pull/730) Fixes nested has_many links in JSONAPI (@kurko)
|
|
||||||
- [#718](https://github.com/rails-api/active_model_serializers/pull/718) Allow overriding the adapter with render option (@ggordon)
|
|
||||||
- [#720](https://github.com/rails-api/active_model_serializers/pull/720) Rename attribute with :key (0.8.x compatibility) (@ggordon)
|
|
||||||
- [#728](https://github.com/rails-api/active_model_serializers/pull/728) Use type as key for linked resources (@kurko)
|
|
||||||
- [#729](https://github.com/rails-api/active_model_serializers/pull/729) Use the new beta build env on Travis (@joshk)
|
|
||||||
- [#703](https://github.com/rails-api/active_model_serializers/pull/703) Support serializer and each_serializer options in renderer (@ggordon, @mieko)
|
|
||||||
- [#727](https://github.com/rails-api/active_model_serializers/pull/727) Includes links inside of linked resources (@kurko)
|
|
||||||
- [#726](https://github.com/rails-api/active_model_serializers/pull/726) Bugfix: include nested has_many associations (@kurko)
|
|
||||||
- [#722](https://github.com/rails-api/active_model_serializers/pull/722) Fix infinite recursion (@ggordon)
|
|
||||||
- [#1](https://github.com/rails-api/active_model_serializers/pull/1) Allow for the implicit use of ArraySerializer when :each_serializer is specified (@mieko)
|
|
||||||
- [#692](https://github.com/rails-api/active_model_serializers/pull/692) Include 'linked' member for json-api collections (@ggordon)
|
|
||||||
- [#714](https://github.com/rails-api/active_model_serializers/pull/714) Define as_json instead of to_json (@guilleiguaran)
|
|
||||||
- [#710](https://github.com/rails-api/active_model_serializers/pull/710) JSON-API: Don't include linked section if associations are empty (@guilleiguaran)
|
|
||||||
- [#711](https://github.com/rails-api/active_model_serializers/pull/711) Fixes rbx gems bundling on TravisCI (@kurko)
|
|
||||||
- [#709](https://github.com/rails-api/active_model_serializers/pull/709) Add type key when association name is different than object type (@guilleiguaran)
|
|
||||||
- [#708](https://github.com/rails-api/active_model_serializers/pull/708) Handle correctly null associations (@guilleiguaran)
|
|
||||||
- [#691](https://github.com/rails-api/active_model_serializers/pull/691) Fix embed option for associations (@jacob-s-son)
|
|
||||||
- [#689](https://github.com/rails-api/active_model_serializers/pull/689) Fix support for custom root in JSON-API adapter (@guilleiguaran)
|
|
||||||
- [#685](https://github.com/rails-api/active_model_serializers/pull/685) Serialize ids as strings in JSON-API adapter (@guilleiguaran)
|
|
||||||
- [#684](https://github.com/rails-api/active_model_serializers/pull/684) Refactor adapters to implement support for array serialization (@guilleiguaran)
|
|
||||||
- [#682](https://github.com/rails-api/active_model_serializers/pull/682) Include root by default in JSON-API serializers (@guilleiguaran)
|
|
||||||
- [#625](https://github.com/rails-api/active_model_serializers/pull/625) Add DSL for urls (@JordanFaust)
|
|
||||||
- [#677](https://github.com/rails-api/active_model_serializers/pull/677) Add support for embed: :ids option for in associations (@guilleiguaran)
|
|
||||||
- [#681](https://github.com/rails-api/active_model_serializers/pull/681) Check superclasses for Serializers (@quainjn)
|
|
||||||
- [#680](https://github.com/rails-api/active_model_serializers/pull/680) Add support for root keys (@NullVoxPopuli)
|
|
||||||
- [#675](https://github.com/rails-api/active_model_serializers/pull/675) Support Rails 4.2.0 (@tricknotes)
|
|
||||||
- [#667](https://github.com/rails-api/active_model_serializers/pull/667) Require only activemodel instead of full rails (@guilleiguaran)
|
|
||||||
- [#653](https://github.com/rails-api/active_model_serializers/pull/653) Add "_test" suffix to JsonApi::HasManyTest filename. (@alexgenco)
|
|
||||||
- [#631](https://github.com/rails-api/active_model_serializers/pull/631) Update build badge URL (@craiglittle)
|
|
||||||
|
|
||||||
### 0.9.0.alpha1 - January 7, 2014
|
|
||||||
|
|
||||||
### 0.9.0.pre
|
|
||||||
|
|
||||||
* The following methods were removed
|
|
||||||
- Model#active\_model\_serializer
|
|
||||||
- Serializer#include!
|
|
||||||
- Serializer#include?
|
|
||||||
- Serializer#attr\_disabled=
|
|
||||||
- Serializer#cache
|
|
||||||
- Serializer#perform\_caching
|
|
||||||
- Serializer#schema (needs more discussion)
|
|
||||||
- Serializer#attribute
|
|
||||||
- Serializer#include\_#{name}? (filter method added)
|
|
||||||
- Serializer#attributes (took a hash)
|
|
||||||
|
|
||||||
* The following things were added
|
|
||||||
- Serializer#filter method
|
|
||||||
- CONFIG object
|
|
||||||
|
|
||||||
* Remove support for ruby 1.8 versions.
|
|
||||||
|
|
||||||
* Require rails >= 3.2.
|
|
||||||
|
|
||||||
* Serializers for associations are being looked up in a parent serializer's namespace first. Same with controllers' namespaces.
|
|
||||||
|
|
||||||
* Added a "prefix" option in case you want to use a different version of serializer.
|
|
||||||
|
|
||||||
* Serializers default namespace can be set in `default_serializer_options` and inherited by associations.
|
|
||||||
|
|
||||||
* [Beginning of rewrite: c65d387705ec534db171712671ba7fcda4f49f68](https://github.com/rails-api/active_model_serializers/commit/c65d387705ec534db171712671ba7fcda4f49f68)
|
|
||||||
@ -1,466 +0,0 @@
|
|||||||
## 0.10.x
|
|
||||||
|
|
||||||
### [0-10-stable (unreleased)](https://github.com/rails-api/active_model_serializers/compare/v0.10.6...0-10-stable)
|
|
||||||
|
|
||||||
Breaking changes:
|
|
||||||
|
|
||||||
Features:
|
|
||||||
|
|
||||||
Fixes:
|
|
||||||
|
|
||||||
Misc:
|
|
||||||
|
|
||||||
### [v0.10.6 (2017-05-01)](https://github.com/rails-api/active_model_serializers/compare/v0.10.5...v0.10.6)
|
|
||||||
|
|
||||||
Fixes:
|
|
||||||
|
|
||||||
- [#1857](https://github.com/rails-api/active_model_serializers/pull/1857) JSON:API does not load belongs_to relation to get identifier id. (@bf4)
|
|
||||||
- [#2119](https://github.com/rails-api/active_model_serializers/pull/2119) JSON:API returns null resource object identifier when 'id' is null. (@bf4)
|
|
||||||
- [#2093](https://github.com/rails-api/active_model_serializers/pull/2093) undef problematic Serializer methods: display, select. (@bf4)
|
|
||||||
|
|
||||||
Misc:
|
|
||||||
|
|
||||||
- [#2104](https://github.com/rails-api/active_model_serializers/pull/2104) Documentation for serializers and rendering. (@cassidycodes)
|
|
||||||
- [#2081](https://github.com/rails-api/active_model_serializers/pull/2081) Documentation for `include` option in adapters. (@charlie-wasp)
|
|
||||||
- [#2120](https://github.com/rails-api/active_model_serializers/pull/2120) Documentation for association options: foreign_key, type, class_name, namespace. (@bf4)
|
|
||||||
|
|
||||||
### [v0.10.5 (2017-03-07)](https://github.com/rails-api/active_model_serializers/compare/v0.10.4...v0.10.5)
|
|
||||||
|
|
||||||
Breaking changes:
|
|
||||||
|
|
||||||
Features:
|
|
||||||
|
|
||||||
- [#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)
|
|
||||||
- [#2057](https://github.com/rails-api/active_model_serializers/pull/2057)
|
|
||||||
Update version constraint for jsonapi-renderer to `['>= 0.1.1.beta1', '< 0.2']`
|
|
||||||
(@jaredbeck)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
Misc:
|
|
||||||
|
|
||||||
- [#2055](https://github.com/rails-api/active_model_serializers/pull/2055)
|
|
||||||
Replace deprecated dependency jsonapi with jsonapi-renderer. (@jaredbeck)
|
|
||||||
- [#2021](https://github.com/rails-api/active_model_serializers/pull/2021) Make test attributes explicit. Tests have Model#associations. (@bf4)
|
|
||||||
- [#1981](https://github.com/rails-api/active_model_serializers/pull/1981) Fix relationship link documentation. (@groyoh)
|
|
||||||
- [#2035](https://github.com/rails-api/active_model_serializers/pull/2035) Document how to disable the logger. (@MSathieu)
|
|
||||||
- [#2039](https://github.com/rails-api/active_model_serializers/pull/2039) Documentation fixes. (@biow0lf)
|
|
||||||
|
|
||||||
### [v0.10.4 (2017-01-06)](https://github.com/rails-api/active_model_serializers/compare/v0.10.3...v0.10.4)
|
|
||||||
|
|
||||||
Misc:
|
|
||||||
|
|
||||||
- [#2005](https://github.com/rails-api/active_model_serializers/pull/2005) Update jsonapi runtime dependency to 0.1.1.beta6, support Ruby 2.4. (@kofronpi)
|
|
||||||
- [#1993](https://github.com/rails-api/active_model_serializers/pull/1993) Swap out KeyTransform for CaseTransform gem for the possibility of native extension use. (@NullVoxPopuli)
|
|
||||||
|
|
||||||
### [v0.10.3 (2016-11-21)](https://github.com/rails-api/active_model_serializers/compare/v0.10.2...v0.10.3)
|
|
||||||
|
|
||||||
Fixes:
|
|
||||||
|
|
||||||
- [#1973](https://github.com/rails-api/active_model_serializers/pull/1973) Fix namespace lookup for collections and has_many relationships (@groyoh)
|
|
||||||
- [#1887](https://github.com/rails-api/active_model_serializers/pull/1887) Make the comment reflect what the function does (@johnnymo87)
|
|
||||||
- [#1890](https://github.com/rails-api/active_model_serializers/issues/1890) Ensure generator inherits from ApplicationSerializer when available (@richmolj)
|
|
||||||
- [#1922](https://github.com/rails-api/active_model_serializers/pull/1922) Make railtie an optional dependency in runtime (@ggpasqualino)
|
|
||||||
- [#1930](https://github.com/rails-api/active_model_serializers/pull/1930) Ensure valid jsonapi when relationship has no links or data (@richmolj)
|
|
||||||
|
|
||||||
Features:
|
|
||||||
|
|
||||||
- [#1757](https://github.com/rails-api/active_model_serializers/pull/1757) Make serializer lookup chain configurable. (@NullVoxPopuli)
|
|
||||||
- [#1968](https://github.com/rails-api/active_model_serializers/pull/1968) (@NullVoxPopuli)
|
|
||||||
- Add controller namespace to default controller lookup
|
|
||||||
- Provide a `namespace` render option
|
|
||||||
- document how set the namespace in the controller for implicit lookup.
|
|
||||||
- [#1791](https://github.com/rails-api/active_model_serializers/pull/1791) (@bf4, @youroff, @NullVoxPopuli)
|
|
||||||
- Added `jsonapi_namespace_separator` config option.
|
|
||||||
- [#1889](https://github.com/rails-api/active_model_serializers/pull/1889) Support key transformation for Attributes adapter (@iancanderson, @danbee)
|
|
||||||
- [#1917](https://github.com/rails-api/active_model_serializers/pull/1917) Add `jsonapi_pagination_links_enabled` configuration option (@richmolj)
|
|
||||||
- [#1797](https://github.com/rails-api/active_model_serializers/pull/1797) Only include 'relationships' when sideloading (@richmolj)
|
|
||||||
|
|
||||||
Fixes:
|
|
||||||
|
|
||||||
- [#1833](https://github.com/rails-api/active_model_serializers/pull/1833) Remove relationship links if they are null (@groyoh)
|
|
||||||
- [#1881](https://github.com/rails-api/active_model_serializers/pull/1881) ActiveModelSerializers::Model correctly works with string keys (@yevhene)
|
|
||||||
|
|
||||||
Misc:
|
|
||||||
- [#1767](https://github.com/rails-api/active_model_serializers/pull/1767) Replace raising/rescuing `CollectionSerializer::NoSerializerError`,
|
|
||||||
throw/catch `:no_serializer`. (@bf4)
|
|
||||||
- [#1839](https://github.com/rails-api/active_model_serializers/pull/1839) `fields` tests demonstrating usage for both attributes and relationships. (@NullVoxPopuli)
|
|
||||||
- [#1812](https://github.com/rails-api/active_model_serializers/pull/1812) add a code of conduct (@corainchicago)
|
|
||||||
|
|
||||||
- [#1878](https://github.com/rails-api/active_model_serializers/pull/1878) Cache key generation for serializers now uses `ActiveSupport::Cache.expand_cache_key` instead of `Array#join` by default and is also overridable. This change should be backward-compatible. (@markiz)
|
|
||||||
|
|
||||||
- [#1799](https://github.com/rails-api/active_model_serializers/pull/1799) Add documentation for setting the adapter. (@cassidycodes)
|
|
||||||
- [#1909](https://github.com/rails-api/active_model_serializers/pull/1909) Add documentation for relationship links. (@vasilakisfil, @NullVoxPopuli)
|
|
||||||
- [#1959](https://github.com/rails-api/active_model_serializers/pull/1959) Add documentation for root. (@shunsuke227ono)
|
|
||||||
- [#1967](https://github.com/rails-api/active_model_serializers/pull/1967) Improve type method documentation. (@yukideluxe)
|
|
||||||
|
|
||||||
### [v0.10.2 (2016-07-05)](https://github.com/rails-api/active_model_serializers/compare/v0.10.1...v0.10.2)
|
|
||||||
|
|
||||||
Fixes:
|
|
||||||
- [#1814](https://github.com/rails-api/active_model_serializers/pull/1814) Ensuring read_multi works with fragment cache
|
|
||||||
- [#1848](https://github.com/rails-api/active_model_serializers/pull/1848) Redefine associations on inherited serializers. (@EhsanYousefi)
|
|
||||||
|
|
||||||
Misc:
|
|
||||||
- [#1808](https://github.com/rails-api/active_model_serializers/pull/1808) Adds documentation for `fields` option. (@luizkowalski)
|
|
||||||
|
|
||||||
### [v0.10.1 (2016-06-16)](https://github.com/rails-api/active_model_serializers/compare/v0.10.0...v0.10.1)
|
|
||||||
|
|
||||||
Features:
|
|
||||||
- [#1668](https://github.com/rails-api/active_model_serializers/pull/1668) Exclude nil and empty links. (@sigmike)
|
|
||||||
- [#1426](https://github.com/rails-api/active_model_serializers/pull/1426) Add ActiveModelSerializers.config.default_includes (@empact)
|
|
||||||
|
|
||||||
Fixes:
|
|
||||||
- [#1754](https://github.com/rails-api/active_model_serializers/pull/1754) Fixes #1759, Grape integration, improves serialization_context
|
|
||||||
missing error message on pagination. Document overriding CollectionSerializer#paginated?. (@bf4)
|
|
||||||
Moved serialization_context creation to Grape formatter, so resource serialization works without explicit calls to the `render` helper method.
|
|
||||||
Added Grape collection tests. (@onomated)
|
|
||||||
- [#1287](https://github.com/rails-api/active_model_serializers/pull/1287) Pass `fields` options from adapter to serializer. (@vasilakisfil)
|
|
||||||
- [#1710](https://github.com/rails-api/active_model_serializers/pull/1710) Prevent association loading when `include_data` option
|
|
||||||
is set to `false`. (@groyoh)
|
|
||||||
- [#1747](https://github.com/rails-api/active_model_serializers/pull/1747) Improve jsonapi mime type registration for Rails 5 (@remear)
|
|
||||||
|
|
||||||
Misc:
|
|
||||||
- [#1734](https://github.com/rails-api/active_model_serializers/pull/1734) Adds documentation for conditional attribute (@lambda2)
|
|
||||||
- [#1685](https://github.com/rails-api/active_model_serializers/pull/1685) Replace `IncludeTree` with `IncludeDirective` from the jsonapi gem.
|
|
||||||
|
|
||||||
### [v0.10.0 (2016-05-17)](https://github.com/rails-api/active_model_serializers/compare/4a2d9853ba7...v0.10.0)
|
|
||||||
|
|
||||||
Breaking changes:
|
|
||||||
- [#1662](https://github.com/rails-api/active_model_serializers/pull/1662) Drop support for Rails 4.0 and Ruby 2.0.0. (@remear)
|
|
||||||
|
|
||||||
Features:
|
|
||||||
- [#1677](https://github.com/rails-api/active_model_serializers/pull/1677) Add `assert_schema`, `assert_request_schema`, `assert_request_response_schema`. (@bf4)
|
|
||||||
- [#1697](https://github.com/rails-api/active_model_serializers/pull/1697) Include actual exception message with custom exceptions;
|
|
||||||
`Test::Schema` exceptions are now `Minitest::Assertion`s. (@bf4)
|
|
||||||
- [#1699](https://github.com/rails-api/active_model_serializers/pull/1699) String/Lambda support for conditional attributes/associations (@mtsmfm)
|
|
||||||
- [#1687](https://github.com/rails-api/active_model_serializers/pull/1687) Only calculate `_cache_digest` (in `cache_key`) when `skip_digest` is false. (@bf4)
|
|
||||||
- [#1647](https://github.com/rails-api/active_model_serializers/pull/1647) Restrict usage of `serializable_hash` options
|
|
||||||
to the ActiveModel::Serialization and ActiveModel::Serializers::JSON interface. (@bf4)
|
|
||||||
|
|
||||||
Fixes:
|
|
||||||
- [#1700](https://github.com/rails-api/active_model_serializers/pull/1700) Support pagination link for Kaminari when no data is returned. (@iamnader)
|
|
||||||
- [#1726](https://github.com/rails-api/active_model_serializers/pull/1726) Adds polymorphic option to association definition which includes association type/nesting in serializer (@cgmckeever)
|
|
||||||
|
|
||||||
Misc:
|
|
||||||
- [#1673](https://github.com/rails-api/active_model_serializers/pull/1673) Adds "How to" guide on using AMS with POROs (@DrSayre)
|
|
||||||
- [#1730](https://github.com/rails-api/active_model_serializers/pull/1730) Adds documentation for overriding default serializer based on conditions (@groyoh/@cgmckeever)
|
|
||||||
|
|
||||||
### [v0.10.0.rc5 (2016-04-04)](https://github.com/rails-api/active_model_serializers/compare/v0.10.0.rc4...v0.10.0.rc5)
|
|
||||||
|
|
||||||
Breaking changes:
|
|
||||||
|
|
||||||
- [#1645](https://github.com/rails-api/active_model_serializers/pull/1645) Changed :dashed key transform to :dash. (@remear)
|
|
||||||
- [#1574](https://github.com/rails-api/active_model_serializers/pull/1574) Default key case for the JsonApi adapter changed to dashed. (@remear)
|
|
||||||
|
|
||||||
Features:
|
|
||||||
- [#1645](https://github.com/rails-api/active_model_serializers/pull/1645) Transform keys referenced in values. (@remear)
|
|
||||||
- [#1650](https://github.com/rails-api/active_model_serializers/pull/1650) Fix serialization scope options `scope`, `scope_name`
|
|
||||||
take precedence over `serialization_scope` in the controller.
|
|
||||||
Fix tests that required tearing down dynamic methods. (@bf4)
|
|
||||||
- [#1644](https://github.com/rails-api/active_model_serializers/pull/1644) Include adapter name in cache key so
|
|
||||||
that the same serializer can be cached per adapter. (@bf4 via #1346 by @kevintyll)
|
|
||||||
- [#1642](https://github.com/rails-api/active_model_serializers/pull/1642) Prefer object.cache_key over the generated
|
|
||||||
cache key. (@bf4 via #1346 by @kevintyll)
|
|
||||||
- [#1637](https://github.com/rails-api/active_model_serializers/pull/1637) Make references to 'ActionController::Base.cache_store' explicit
|
|
||||||
in order to avoid issues when application controllers inherit from 'ActionController::API'. (@ncuesta)
|
|
||||||
- [#1633](https://github.com/rails-api/active_model_serializers/pull/1633) Yield 'serializer' to serializer association blocks. (@bf4)
|
|
||||||
- [#1616](https://github.com/rails-api/active_model_serializers/pull/1616) SerializableResource handles no serializer like controller. (@bf4)
|
|
||||||
- [#1618](https://github.com/rails-api/active_model_serializers/issues/1618) Get collection root key for
|
|
||||||
empty collection from explicit serializer option, when possible. (@bf4)
|
|
||||||
- [#1574](https://github.com/rails-api/active_model_serializers/pull/1574) Provide key translation. (@remear)
|
|
||||||
- [#1494](https://github.com/rails-api/active_model_serializers/pull/1494) Make serializers serializalbe
|
|
||||||
(using the Attributes adapter by default). (@bf4)
|
|
||||||
- [#1550](https://github.com/rails-api/active_model_serializers/pull/1550) Add
|
|
||||||
Rails url_helpers to `SerializationContext` for use in links. (@remear, @bf4)
|
|
||||||
- [#1004](https://github.com/rails-api/active_model_serializers/pull/1004) JSON API errors object implementation.
|
|
||||||
- Only implements `detail` and `source` as derived from `ActiveModel::Error`
|
|
||||||
- Provides checklist of remaining questions and remaining parts of the spec.
|
|
||||||
- [#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:
|
|
||||||
- [#1657](https://github.com/rails-api/active_model_serializers/pull/1657) Add missing missing require "active_support/json". (@andreaseger)
|
|
||||||
- [#1661](https://github.com/rails-api/active_model_serializers/pull/1661) Fixes `read_attribute_for_serialization` not
|
|
||||||
seeing methods defined in serialization superclass (#1653, #1658, #1660), introduced in #1650. (@bf4)
|
|
||||||
- [#1651](https://github.com/rails-api/active_model_serializers/pull/1651) Fix deserialization of nil relationships. (@NullVoxPopuli)
|
|
||||||
- [#1480](https://github.com/rails-api/active_model_serializers/pull/1480) Fix setting of cache_store from Rails configuration. (@bf4)
|
|
||||||
Fix unintentional mutating of value in memory cache store. (@groyoh)
|
|
||||||
- [#1622](https://github.com/rails-api/active_model_serializers/pull/1622) Fragment cache changed from per-record to per-serializer.
|
|
||||||
Now, two serializers that use the same model may be separately cached. (@lserman)
|
|
||||||
- [#1478](https://github.com/rails-api/active_model_serializers/pull/1478) Cache store will now be correctly set when serializers are
|
|
||||||
loaded *before* Rails initializes. (@bf4)
|
|
||||||
- [#1570](https://github.com/rails-api/active_model_serializers/pull/1570) Fixed pagination issue with last page size. (@bmorrall)
|
|
||||||
- [#1516](https://github.com/rails-api/active_model_serializers/pull/1516) 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)
|
|
||||||
|
|
||||||
Misc:
|
|
||||||
- [#1608](https://github.com/rails-api/active_model_serializers/pull/1608) Move SerializableResource to ActiveModelSerializers (@groyoh)
|
|
||||||
- [#1602](https://github.com/rails-api/active_model_serializers/pull/1602) Add output examples to Adapters docs (@remear)
|
|
||||||
- [#1557](https://github.com/rails-api/active_model_serializers/pull/1557) Update docs regarding overriding the root key (@Jwan622)
|
|
||||||
- [#1471](https://github.com/rails-api/active_model_serializers/pull/1471) [Cleanup] Serializer caching is its own concern. (@bf4)
|
|
||||||
- [#1482](https://github.com/rails-api/active_model_serializers/pull/1482) Document JSON API implementation defs and progress in class. (@bf4)
|
|
||||||
- [#1551](https://github.com/rails-api/active_model_serializers/pull/1551) Added codebeat badge (@korzonek)
|
|
||||||
- [#1527](https://github.com/rails-api/active_model_serializers/pull/1527) Refactor fragment cache class. (@groyoh)
|
|
||||||
- [#1560](https://github.com/rails-api/active_model_serializers/pull/1560) Update rubocop and address its warnings. (@bf4 @groyoh)
|
|
||||||
- [#1545](https://github.com/rails-api/active_model_serializers/pull/1545) Document how to pass arbitrary options to the
|
|
||||||
serializer (@CodedBeardedSignedTaylor)
|
|
||||||
- [#1496](https://github.com/rails-api/active_model_serializers/pull/1496) Run all branches against JRuby on CI (@nadavshatz)
|
|
||||||
- [#1559](https://github.com/rails-api/active_model_serializers/pull/1559) Add a deprecation DSL. (@bf4 @groyoh)
|
|
||||||
- [#1543](https://github.com/rails-api/active_model_serializers/pull/1543) Add the changes missing from #1535. (@groyoh)
|
|
||||||
- [#1535](https://github.com/rails-api/active_model_serializers/pull/1535) Move the adapter and adapter folder to
|
|
||||||
active_model_serializers folder and changes the module namespace. (@domitian @bf4)
|
|
||||||
- [#1497](https://github.com/rails-api/active_model_serializers/pull/1497) Add JRuby-9000 to appveyor.yml(@corainchicago)
|
|
||||||
- [#1420](https://github.com/rails-api/active_model_serializers/pull/1420) Adds tests and documentation for polymorphism(@marcgarreau)
|
|
||||||
|
|
||||||
|
|
||||||
### [v0.10.0.rc4 (2016-01-27)](https://github.com/rails-api/active_model_serializers/compare/v0.10.0.rc3...v0.10.0.rc4)
|
|
||||||
Breaking changes:
|
|
||||||
|
|
||||||
- [#1360](https://github.com/rails-api/active_model_serializers/pull/1360)
|
|
||||||
[#1369](https://github.com/rails-api/active_model_serializers/pull/1369) Drop support for Ruby 1.9.3 (@karaAJC, @maurogeorge)
|
|
||||||
- [#1131](https://github.com/rails-api/active_model_serializers/pull/1131) Remove Serializer#root_name (@beauby)
|
|
||||||
- [#1138](https://github.com/rails-api/active_model_serializers/pull/1138) Introduce Adapter::Base (@bf4)
|
|
||||||
* Adapters now inherit Adapter::Base. 'Adapter' is now a module, no longer a class.
|
|
||||||
* using a class as a namespace that you also inherit from is complicated and circular at times i.e.
|
|
||||||
buggy (see https://github.com/rails-api/active_model_serializers/pull/1177)
|
|
||||||
* The class methods on Adapter aren't necessarily related to the instance methods, they're more
|
|
||||||
Adapter functions.
|
|
||||||
* named `Base` because it's a Rails-ism.
|
|
||||||
* It helps to isolate and highlight what the Adapter interface actually is.
|
|
||||||
- [#1418](https://github.com/rails-api/active_model_serializers/pull/1418)
|
|
||||||
serialized collections now use the root option as is; now, only the
|
|
||||||
root derived from the serializer or object is always pluralized.
|
|
||||||
|
|
||||||
Features:
|
|
||||||
|
|
||||||
- [#1406](https://github.com/rails-api/active_model_serializers/pull/1406) Allow for custom dynamic values in JSON API links (@beauby)
|
|
||||||
- [#1270](https://github.com/rails-api/active_model_serializers/pull/1270) Adds `assert_response_schema` test helper (@maurogeorge)
|
|
||||||
- [#1099](https://github.com/rails-api/active_model_serializers/pull/1099) Adds `assert_serializer` test helper (@maurogeorge)
|
|
||||||
- [#1403](https://github.com/rails-api/active_model_serializers/pull/1403) Add support for if/unless on attributes/associations (@beauby)
|
|
||||||
- [#1248](https://github.com/rails-api/active_model_serializers/pull/1248) Experimental: Add support for JSON API deserialization (@beauby)
|
|
||||||
- [#1378](https://github.com/rails-api/active_model_serializers/pull/1378) Change association blocks
|
|
||||||
to be evaluated in *serializer* scope, rather than *association* scope. (@bf4)
|
|
||||||
* Syntax changes from e.g.
|
|
||||||
`has_many :titles do customers.pluck(:title) end` (in #1356) to
|
|
||||||
`has_many :titles do object.customers.pluck(:title) end`
|
|
||||||
- [#1356](https://github.com/rails-api/active_model_serializers/pull/1356) Add inline syntax for
|
|
||||||
attributes and associations (@bf4 @beauby @noahsilas)
|
|
||||||
* Allows defining attributes so that they don't conflict with existing methods. e.g. `attribute
|
|
||||||
:title do 'Mr. Topum Hat' end`
|
|
||||||
* Allows defining associations so that they don't conflict with existing methods. e.g. `has_many
|
|
||||||
:titles do customers.pluck(:title) end`
|
|
||||||
* Allows dynamic associations, as compared to compare to using
|
|
||||||
[`virtual_value`](https://github.com/rails-api/active_model_serializers/pull/1356#discussion_r47146466).
|
|
||||||
e.g. `has_many :reviews, virtual_value: [{ id: 1 }, { id: 2 }]`
|
|
||||||
* Removes dynamically defined methods on the serializer
|
|
||||||
- [#1336](https://github.com/rails-api/active_model_serializers/pull/1336) Added support for Grape >= 0.13, < 1.0 (@johnhamelink)
|
|
||||||
- [#1322](https://github.com/rails-api/active_model_serializers/pull/1322) Instrumenting rendering of resources (@bf4, @maurogeorge)
|
|
||||||
- [#1291](https://github.com/rails-api/active_model_serializers/pull/1291) Add logging (@maurogeorge)
|
|
||||||
- [#1272](https://github.com/rails-api/active_model_serializers/pull/1272) Add PORO serializable base class: ActiveModelSerializers::Model (@bf4)
|
|
||||||
- [#1255](https://github.com/rails-api/active_model_serializers/pull/1255) Make more class attributes inheritable (@bf4)
|
|
||||||
- [#1249](https://github.com/rails-api/active_model_serializers/pull/1249) Inheritance of serializer inheriting the cache configuration(@Rodrigora)
|
|
||||||
- [#1247](https://github.com/rails-api/active_model_serializers/pull/1247) Add support for toplevel JSON API links (@beauby)
|
|
||||||
- [#1246](https://github.com/rails-api/active_model_serializers/pull/1246) Add support for resource-level JSON API links (@beauby)
|
|
||||||
- [#1225](https://github.com/rails-api/active_model_serializers/pull/1225) Better serializer lookup, use nested serializer when it exists (@beauby)
|
|
||||||
- [#1213](https://github.com/rails-api/active_model_serializers/pull/1213) `type` directive for serializer to control type field with json-api adapter (@youroff)
|
|
||||||
- [#1172](https://github.com/rails-api/active_model_serializers/pull/1172) Better serializer registration, get more than just the first module (@bf4)
|
|
||||||
- [#1158](https://github.com/rails-api/active_model_serializers/pull/1158) Add support for wildcards in `include` option (@beauby)
|
|
||||||
- [#1127](https://github.com/rails-api/active_model_serializers/pull/1127) Add support for nested
|
|
||||||
associations for JSON and Attributes adapters via the `include` option (@NullVoxPopuli, @beauby).
|
|
||||||
- [#1050](https://github.com/rails-api/active_model_serializers/pull/1050) Add support for toplevel jsonapi member (@beauby, @bf4)
|
|
||||||
- [#1251](https://github.com/rails-api/active_model_serializers/pull/1251) Rename ArraySerializer to
|
|
||||||
CollectionSerializer for clarity, add ActiveModelSerializers.config.collection_serializer (@bf4)
|
|
||||||
- [#1295](https://github.com/rails-api/active_model_serializers/pull/1295) Add config `serializer_lookup_enabled` that,
|
|
||||||
when disabled, requires serializers to explicitly specified. (@trek)
|
|
||||||
|
|
||||||
Fixes:
|
|
||||||
|
|
||||||
- [#1352](https://github.com/rails-api/active_model_serializers/pull/1352) Fix generators; Isolate Rails-specifc code in Railties (@dgynn, @bf4)
|
|
||||||
- [#1384](https://github.com/rails-api/active_model_serializers/pull/1384)Fix database state leaking across tests (@bf4)
|
|
||||||
- [#1297](https://github.com/rails-api/active_model_serializers/pull/1297) Fix `fields` option to restrict relationships as well (@beauby)
|
|
||||||
- [#1239](https://github.com/rails-api/active_model_serializers/pull/1239) Fix duplicates in JSON API compound documents (@beauby)
|
|
||||||
- [#1214](https://github.com/rails-api/active_model_serializers/pull/1214) retrieve the key from the reflection options when building associations (@NullVoxPopuli, @hut8)
|
|
||||||
- [#1358](https://github.com/rails-api/active_model_serializers/pull/1358) Handle serializer file paths with spaces (@rwstauner, @bf4)
|
|
||||||
- [#1195](https://github.com/rails-api/active_model_serializers/pull/1195) Fix id override (@beauby)
|
|
||||||
- [#1185](https://github.com/rails-api/active_model_serializers/pull/1185) Fix options passing in Json and Attributes adapters (@beauby)
|
|
||||||
|
|
||||||
Misc:
|
|
||||||
|
|
||||||
- [#1383](https://github.com/rails-api/active_model_serializers/pull/1383) Simplify reflections handling (@beauby)
|
|
||||||
- [#1370](https://github.com/rails-api/active_model_serializers/pull/1370) Simplify attributes handling via a mixin (@beauby)
|
|
||||||
- [#1301](https://github.com/rails-api/active_model_serializers/pull/1301) Mapping JSON API spec / schema to AMS (@bf4)
|
|
||||||
- [#1271](https://github.com/rails-api/active_model_serializers/pull/1271) Handle no serializer source file to digest (@bf4)
|
|
||||||
- [#1260](https://github.com/rails-api/active_model_serializers/pull/1260) Serialization and Cache Documentation (@bf4)
|
|
||||||
- [#1259](https://github.com/rails-api/active_model_serializers/pull/1259) Add more info to CONTRIBUTING (@bf4)
|
|
||||||
- [#1233](https://github.com/rails-api/active_model_serializers/pull/1233) Top-level meta and meta_key options no longer handled at serializer level (@beauby)
|
|
||||||
- [#1232](https://github.com/rails-api/active_model_serializers/pull/1232) fields option no longer handled at serializer level (@beauby)
|
|
||||||
- [#1220](https://github.com/rails-api/active_model_serializers/pull/1220) Remove empty rubocop.rake (@maurogeorge)
|
|
||||||
- [#1178](https://github.com/rails-api/active_model_serializers/pull/1178) env CAPTURE_STDERR=false lets devs see hard failures (@bf4)
|
|
||||||
- [#1177](https://github.com/rails-api/active_model_serializers/pull/1177) Remove Adapter autoloads in favor of require (@bf4)
|
|
||||||
- [#1117](https://github.com/rails-api/active_model_serializers/pull/1117) FlattenJson adapter no longer inherits Json adapter, renamed to Attributes (@bf4)
|
|
||||||
- [#1171](https://github.com/rails-api/active_model_serializers/pull/1171) add require statements to top of file (@shicholas)
|
|
||||||
- [#1167](https://github.com/rails-api/active_model_serializers/pull/1167) Delegate Serializer.attributes to Serializer.attribute (@bf4)
|
|
||||||
- [#1174](https://github.com/rails-api/active_model_serializers/pull/1174) Consistently refer to the 'JSON API' and the 'JsonApi' adapter (@bf4)
|
|
||||||
- [#1173](https://github.com/rails-api/active_model_serializers/pull/1173) Comment private accessor warnings (@bf4)
|
|
||||||
- [#1166](https://github.com/rails-api/active_model_serializers/pull/1166) Prefer methods over instance variables (@bf4)
|
|
||||||
- [#1168](https://github.com/rails-api/active_model_serializers/pull/1168) Fix appveyor failure cache not being expired (@bf4)
|
|
||||||
- [#1161](https://github.com/rails-api/active_model_serializers/pull/1161) Remove duplicate test helper (@bf4)
|
|
||||||
- [#1360](https://github.com/rails-api/active_model_serializers/pull/1360) Update CI to test 2.2.2 -> 2.2.3 (@karaAJC)
|
|
||||||
- [#1371](https://github.com/rails-api/active_model_serializers/pull/1371) Refactor, update, create documentation (@bf4)
|
|
||||||
|
|
||||||
### [v0.10.0.rc3 (2015-09-16)](https://github.com/rails-api/active_model_serializers/compare/v0.10.0.rc2...v0.10.0.rc3)
|
|
||||||
- [#1129](https://github.com/rails-api/active_model_serializers/pull/1129) Remove SerializableResource.serialize in favor of `.new` (@bf4)
|
|
||||||
- [#1155](https://github.com/rails-api/active_model_serializers/pull/1155) Outside controller use tutorial (@CodedBeardedSignedTaylor)
|
|
||||||
- [#1154](https://github.com/rails-api/active_model_serializers/pull/1154) Rubocop fixes for issues introduced by #1089 (@NullVoxPopuli)
|
|
||||||
- [#1089](https://github.com/rails-api/active_model_serializers/pull/1089) Add ActiveModelSerializers.logger with default null device (@bf4)
|
|
||||||
- [#1109](https://github.com/rails-api/active_model_serializers/pull/1109) Make better use of Minitest's lifecycle (@bf4)
|
|
||||||
- [#1144](https://github.com/rails-api/active_model_serializers/pull/1144) Fix Markdown to adapters documentation (@bacarini)
|
|
||||||
- [#1121](https://github.com/rails-api/active_model_serializers/pull/1121) Refactor `add_links` in JSONAPI adapter. (@beauby)
|
|
||||||
- [#1150](https://github.com/rails-api/active_model_serializers/pull/1150) Remove legacy method accidentally reintroduced in #1017 (@beauby)
|
|
||||||
- [#1149](https://github.com/rails-api/active_model_serializers/pull/1149) Update README with nested included association example. (@mattmueller)
|
|
||||||
- [#1110](https://github.com/rails-api/active_model_serializers/pull/1110) Add lint tests for AR models (@beauby)
|
|
||||||
- [#1131](https://github.com/rails-api/active_model_serializers/pull/1131) Extended format for JSONAPI `include` option (@beauby)
|
|
||||||
* adds extended format for `include` option to JsonApi adapter
|
|
||||||
- [#1142](https://github.com/rails-api/active_model_serializers/pull/1142) Updating wording on cache expiry in README (@leighhalliday)
|
|
||||||
- [#1140](https://github.com/rails-api/active_model_serializers/pull/1140) Fix typo in fieldset exception (@lautis)
|
|
||||||
- [#1132](https://github.com/rails-api/active_model_serializers/pull/1132) Get rid of unnecessary instance variables, and implied dependencies. (@beauby)
|
|
||||||
- [#1139](https://github.com/rails-api/active_model_serializers/pull/1139) Documentation for serializing resources without render (@PericlesTheo)
|
|
||||||
- [#1017](https://github.com/rails-api/active_model_serializers/pull/1017) Make Adapters registerable so they are not namespace-constrained (@bf4)
|
|
||||||
- [#1120](https://github.com/rails-api/active_model_serializers/pull/1120) Add windows platform to loading sqlite3 (@Eric-Guo)
|
|
||||||
- [#1123](https://github.com/rails-api/active_model_serializers/pull/1123) Remove url options (@bacarini)
|
|
||||||
- [#1093](https://github.com/rails-api/active_model_serializers/pull/1093) Factor `with_adapter` + force cache clear before each test. (@beauby)
|
|
||||||
- [#1095](https://github.com/rails-api/active_model_serializers/pull/1095) Add documentation about configuration options. (@beauby)
|
|
||||||
- [#1069](https://github.com/rails-api/active_model_serializers/pull/1069) Add test coverage; account for no artifacts on CI (@bf4)
|
|
||||||
- [#1103](https://github.com/rails-api/active_model_serializers/pull/1103) Move `id` and `json_api_type` methods from `Serializer` to `JsonApi`. (@beauby)
|
|
||||||
- [#1106](https://github.com/rails-api/active_model_serializers/pull/1106) Add Style enforcer (via Rubocop) (@bf4)
|
|
||||||
- [#1079](https://github.com/rails-api/active_model_serializers/pull/1079) Add ArraySerializer#object like Serializer (@bf4)
|
|
||||||
- [#1096](https://github.com/rails-api/active_model_serializers/pull/1096) Fix definition of serializer attributes with multiple calls to `attri… (@beauby)
|
|
||||||
- [#1105](https://github.com/rails-api/active_model_serializers/pull/1105) Add ActiveRecord-backed fixtures. (@beauby)
|
|
||||||
- [#1108](https://github.com/rails-api/active_model_serializers/pull/1108) Better lint (@bf4)
|
|
||||||
- [#1102](https://github.com/rails-api/active_model_serializers/pull/1102) Remove remains of `embed` option. (@beauby)
|
|
||||||
- [#1090](https://github.com/rails-api/active_model_serializers/pull/1090) Clarify AMS dependencies (@bf4)
|
|
||||||
- [#1081](https://github.com/rails-api/active_model_serializers/pull/1081) Add configuration option to set resource type to singular/plural (@beauby)
|
|
||||||
- [#1067](https://github.com/rails-api/active_model_serializers/pull/1067) Fix warnings (@bf4)
|
|
||||||
- [#1066](https://github.com/rails-api/active_model_serializers/pull/1066) Adding appveyor to the project (@joaomdmoura, @Eric-Guo, @bf4)
|
|
||||||
- [#1071](https://github.com/rails-api/active_model_serializers/pull/1071) Make testing suite running and pass in Windows (@Eric-Guo, @bf4)
|
|
||||||
- [#1041](https://github.com/rails-api/active_model_serializers/pull/1041) Adding pagination links (@bacarini)
|
|
||||||
* adds support for `pagination links` at top level of JsonApi adapter
|
|
||||||
- [#1063](https://github.com/rails-api/active_model_serializers/pull/1063) Lead by example: lint PORO model (@bf4)
|
|
||||||
- [#1](https://github.com/rails-api/active_model_serializers/pull/1) Test caller line parsing and digesting (@bf4)
|
|
||||||
- [#1048](https://github.com/rails-api/active_model_serializers/pull/1048) Let FlattenJson adapter decide it doesn't include meta (@bf4)
|
|
||||||
- [#1060](https://github.com/rails-api/active_model_serializers/pull/1060) Update fragment cache to support namespaced objects (@aaronlerch)
|
|
||||||
- [#1052](https://github.com/rails-api/active_model_serializers/pull/1052) Use underscored json_root when serializing a collection (@whatthewhat)
|
|
||||||
- [#1051](https://github.com/rails-api/active_model_serializers/pull/1051) Fix some invalid JSON in docs (@tjschuck)
|
|
||||||
- [#1049](https://github.com/rails-api/active_model_serializers/pull/1049) Fix incorrect s/options = {}/options ||= {} (@bf4)
|
|
||||||
- [#1037](https://github.com/rails-api/active_model_serializers/pull/1037) allow for type attribute (@lanej)
|
|
||||||
- [#1034](https://github.com/rails-api/active_model_serializers/pull/1034) allow id attribute to be overriden (@lanej)
|
|
||||||
- [#1035](https://github.com/rails-api/active_model_serializers/pull/1035) Fixed Comments highlight (@artLopez)
|
|
||||||
- [#1031](https://github.com/rails-api/active_model_serializers/pull/1031) Disallow to define multiple associations at once (@bolshakov)
|
|
||||||
- [#1032](https://github.com/rails-api/active_model_serializers/pull/1032) Wrap railtie requirement with rescue (@elliotlarson)
|
|
||||||
- [#1026](https://github.com/rails-api/active_model_serializers/pull/1026) Bump Version Number to 0.10.0.rc2 (@jfelchner)
|
|
||||||
- [#985](https://github.com/rails-api/active_model_serializers/pull/985) Associations implementation refactoring (@bolshakov)
|
|
||||||
- [#954](https://github.com/rails-api/active_model_serializers/pull/954) Encapsulate serialization in ActiveModel::SerializableResource (@bf4)
|
|
||||||
- [#972](https://github.com/rails-api/active_model_serializers/pull/972) Capture app warnings on test run (@bf4)
|
|
||||||
- [#1019](https://github.com/rails-api/active_model_serializers/pull/1019) Improve README.md (@baojjeu)
|
|
||||||
- [#998](https://github.com/rails-api/active_model_serializers/pull/998) Changing root to model class name (@joaomdmoura)
|
|
||||||
- [#1006](https://github.com/rails-api/active_model_serializers/pull/1006) Fix adapter inflection bug for api -> API (@bf4)
|
|
||||||
- [#1016](https://github.com/rails-api/active_model_serializers/pull/1016) require rails/railtie before subclassing Rails::Railtie (@bf4)
|
|
||||||
- [#1013](https://github.com/rails-api/active_model_serializers/pull/1013) Root option with empty array support (@vyrak, @mareczek)
|
|
||||||
- [#994](https://github.com/rails-api/active_model_serializers/pull/994) Starting Docs structure (@joaomdmoura)
|
|
||||||
- [#1007](https://github.com/rails-api/active_model_serializers/pull/1007) Bug fix for ArraySerializer json_key (@jiajiawang)
|
|
||||||
- [#1003](https://github.com/rails-api/active_model_serializers/pull/1003) Fix transient test failures (@Rodrigora)
|
|
||||||
- [#996](https://github.com/rails-api/active_model_serializers/pull/996) Add linter for serializable resource (@bf4)
|
|
||||||
- [#990](https://github.com/rails-api/active_model_serializers/pull/990) Adding json-api meta test (@joaomdmoura)
|
|
||||||
- [#984](https://github.com/rails-api/active_model_serializers/pull/984) Add option "key" to serializer associations (@Rodrigora)
|
|
||||||
- [#982](https://github.com/rails-api/active_model_serializers/pull/982) Fix typo (@bf4)
|
|
||||||
- [#981](https://github.com/rails-api/active_model_serializers/pull/981) Remove unused PORO#to_param (@bf4)
|
|
||||||
- [#978](https://github.com/rails-api/active_model_serializers/pull/978) fix generators template bug (@regonn)
|
|
||||||
- [#975](https://github.com/rails-api/active_model_serializers/pull/975) Fixes virtual value not being used (@GriffinHeart)
|
|
||||||
- [#970](https://github.com/rails-api/active_model_serializers/pull/970) Fix transient tests failures (@Rodrigora)
|
|
||||||
- [#962](https://github.com/rails-api/active_model_serializers/pull/962) Rendering objects that doesn't have serializers (@bf4, @joaomdmoura, @JustinAiken)
|
|
||||||
- [#939](https://github.com/rails-api/active_model_serializers/pull/939) Use a more precise generated cache key (@aaronlerch)
|
|
||||||
- [#971](https://github.com/rails-api/active_model_serializers/pull/971) Restore has_one to generator (@bf4)
|
|
||||||
- [#965](https://github.com/rails-api/active_model_serializers/pull/965) options fedault valueserializable_hash and as_json (@bf4)
|
|
||||||
- [#959](https://github.com/rails-api/active_model_serializers/pull/959) TYPO on README.md (@kangkyu)
|
|
||||||
|
|
||||||
### [v0.10.0.rc2 (2015-06-16)](https://github.com/rails-api/active_model_serializers/compare/v0.10.0.rc1...v0.10.0.rc2)
|
|
||||||
- [#958](https://github.com/rails-api/active_model_serializers/pull/958) Splitting json adapter into two (@joaomdmoura)
|
|
||||||
* adds FlattenJSON as default adapter
|
|
||||||
- [#953](https://github.com/rails-api/active_model_serializers/pull/953) use model name to determine the type (@lsylvester)
|
|
||||||
* uses model name to determine the type
|
|
||||||
- [#949](https://github.com/rails-api/active_model_serializers/pull/949) Don't pass serializer option to associated serializers (@bf4, @edwardloveall)
|
|
||||||
- [#902](https://github.com/rails-api/active_model_serializers/pull/902) Added serializer file digest to the cache_key (@cristianbica)
|
|
||||||
- [#948](https://github.com/rails-api/active_model_serializers/pull/948) AMS supports JSONAPI 1.0 instead of RC4 (@SeyZ)
|
|
||||||
- [#936](https://github.com/rails-api/active_model_serializers/pull/936) Include meta when using json adapter with custom root (@chrisbranson)
|
|
||||||
- [#942](https://github.com/rails-api/active_model_serializers/pull/942) Small code styling issue (@thiagofm)
|
|
||||||
- [#930](https://github.com/rails-api/active_model_serializers/pull/930) Reverting PR #909 (@joaomdmoura)
|
|
||||||
- [#924](https://github.com/rails-api/active_model_serializers/pull/924) Avoid unnecessary calls to attribute methods when fragment caching (@navinpeiris)
|
|
||||||
- [#925](https://github.com/rails-api/active_model_serializers/pull/925) Updates JSON API Adapter to generate RC4 schema (@benedikt)
|
|
||||||
* adds JSON API support 1.0
|
|
||||||
- [#918](https://github.com/rails-api/active_model_serializers/pull/918) Adding rescue_with_handler to clear state (@ryansch)
|
|
||||||
- [#909](https://github.com/rails-api/active_model_serializers/pull/909) Defining Json-API Adapter as Default (@joaomdmoura)
|
|
||||||
* remove root key option and split JSON adapter
|
|
||||||
- [#914](https://github.com/rails-api/active_model_serializers/pull/914) Prevent possible duplicated attributes in serializer (@groyoh)
|
|
||||||
- [#880](https://github.com/rails-api/active_model_serializers/pull/880) Inabling subclasses serializers to inherit attributes (@groyoh)
|
|
||||||
- [#913](https://github.com/rails-api/active_model_serializers/pull/913) Avoiding the serializer option when instantiating a new one for ArraySerializer Fixed #911 (@groyoh)
|
|
||||||
- [#897](https://github.com/rails-api/active_model_serializers/pull/897) Allow to define custom serializer for given class (@imanel)
|
|
||||||
- [#892](https://github.com/rails-api/active_model_serializers/pull/892) Fixed a bug that appeared when json adapter serialize a nil association (@groyoh)
|
|
||||||
- [#895](https://github.com/rails-api/active_model_serializers/pull/895) Adding a test to cover 'meta' and 'meta_key' attr_readers (@adomokos)
|
|
||||||
- [#894](https://github.com/rails-api/active_model_serializers/pull/894) Fixing typos in README.md (@adomokos)
|
|
||||||
- [#888](https://github.com/rails-api/active_model_serializers/pull/888) Changed duplicated test name in action controller test (@groyoh)
|
|
||||||
- [#890](https://github.com/rails-api/active_model_serializers/pull/890) Remove unused method `def_serializer` (@JustinAiken)
|
|
||||||
- [#887](https://github.com/rails-api/active_model_serializers/pull/887) Fixing tests on JRuby (@joaomdmoura)
|
|
||||||
- [#885](https://github.com/rails-api/active_model_serializers/pull/885) Updates rails versions for test and dev (@tonyta)
|
|
||||||
|
|
||||||
### [v0.10.0.rc1 (2015-04-22)](https://github.com/rails-api/active_model_serializers/compare/86fc7d7227f3ce538fcb28c1e8c7069ce311f0e1...v0.10.0.rc1)
|
|
||||||
- [#810](https://github.com/rails-api/active_model_serializers/pull/810) Adding Fragment Cache to AMS (@joaomdmoura)
|
|
||||||
* adds fragment cache support
|
|
||||||
- [#868](https://github.com/rails-api/active_model_serializers/pull/868) Fixed a bug that appears when a nil association is included (@groyoh)
|
|
||||||
- [#861](https://github.com/rails-api/active_model_serializers/pull/861) README: Add emphasis to single-word difference (@machty)
|
|
||||||
- [#858](https://github.com/rails-api/active_model_serializers/pull/858) Included resource fixes (@mateomurphy)
|
|
||||||
- [#853](https://github.com/rails-api/active_model_serializers/pull/853) RC3 Updates for JSON API (@mateomurphy)
|
|
||||||
- [#852](https://github.com/rails-api/active_model_serializers/pull/852) Fix options merge order in `each_association` (@mateomurphy)
|
|
||||||
- [#850](https://github.com/rails-api/active_model_serializers/pull/850) Use association value for determining serializer used (@mateomurphy)
|
|
||||||
- [#843](https://github.com/rails-api/active_model_serializers/pull/843) Remove the mailing list from the README (@JoshSmith)
|
|
||||||
- [#842](https://github.com/rails-api/active_model_serializers/pull/842) Add notes on how you can help to contributing documentation (@JoshSmith)
|
|
||||||
- [#833](https://github.com/rails-api/active_model_serializers/pull/833) Cache serializers for class (@lsylvester)
|
|
||||||
- [#837](https://github.com/rails-api/active_model_serializers/pull/837) Store options in array serializers (@kurko)
|
|
||||||
- [#836](https://github.com/rails-api/active_model_serializers/pull/836) Makes passed in options accessible inside serializers (@kurko)
|
|
||||||
- [#773](https://github.com/rails-api/active_model_serializers/pull/773) Make json api adapter 'include' option accept an array (@sweatypitts)
|
|
||||||
- [#830](https://github.com/rails-api/active_model_serializers/pull/830) Add contributing readme (@JoshSmith)
|
|
||||||
- [#811](https://github.com/rails-api/active_model_serializers/pull/811) Reimplement serialization scope and scope_name (@mateomurphy)
|
|
||||||
- [#725](https://github.com/rails-api/active_model_serializers/pull/725) Support has_one to be compatible with 0.8.x (@ggordon)
|
|
||||||
* adds `has_one` attribute for backwards compatibility
|
|
||||||
- [#822](https://github.com/rails-api/active_model_serializers/pull/822) Replace has_one with attribute in template (@bf4)
|
|
||||||
- [#821](https://github.com/rails-api/active_model_serializers/pull/821) Fix explicit serializer for associations (@wjordan)
|
|
||||||
- [#798](https://github.com/rails-api/active_model_serializers/pull/798) Fix lost test `test_include_multiple_posts_and_linked` (@donbobka)
|
|
||||||
- [#807](https://github.com/rails-api/active_model_serializers/pull/807) Add Overriding attribute methods section to README. (@alexstophel)
|
|
||||||
- [#693](https://github.com/rails-api/active_model_serializers/pull/693) Cache Support at AMS 0.10.0 (@joaomdmoura)
|
|
||||||
* adds cache support to attributes and associations.
|
|
||||||
- [#792](https://github.com/rails-api/active_model_serializers/pull/792) Association overrides (@kurko)
|
|
||||||
* adds method to override association
|
|
||||||
- [#794](https://github.com/rails-api/active_model_serializers/pull/794) add to_param for correct URL generation (@carlesjove)
|
|
||||||
|
|
||||||
### v0.10.0-pre
|
|
||||||
|
|
||||||
- [Introduce Adapter](https://github.com/rails-api/active_model_serializers/commit/f00fe5595ddf741dc26127ed8fe81adad833ead5)
|
|
||||||
- Prefer `ActiveModel::Serializer` to `ActiveModelSerializers`:
|
|
||||||
- [Namespace](https://github.com/rails-api/active_model_serializers/commit/729a823868e8c7ac86c653fcc7100ee511e08cb6#diff-fe7aa2941c19a41ccea6e52940d84016).
|
|
||||||
- [README](https://github.com/rails-api/active_model_serializers/commit/4a2d9853ba7486acc1747752982aa5650e7fd6e9).
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
## Prehistory
|
|
||||||
|
|
||||||
- [Changing Serialization/Serializers namespace to `Serializable` (November 30, 2011)](https://github.com/rails/rails/commit/8896b4fdc8a543157cdf4dfc378607ebf6c10ab0)
|
|
||||||
- [Merge branch 'serializers'. This implements the ActiveModel::Serializer object. Includes code, tests, generators and guides. From José and Yehuda with love.](https://github.com/rails/rails/commit/fcacc6986ab60f1fb2e423a73bf47c7abd7b191d)
|
|
||||||
- But [was reverted](https://github.com/rails/rails/commit/5b2eb64ceb08cd005dc06b721935de5853971473).
|
|
||||||
'[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)
|
|
||||||
- [Creation of `ActionController::Serialization`, initial serializer
|
|
||||||
support (September, 26 2011)](https://github.com/rails/rails/commit/8ff7693a8dc61f43fc4eaf72ed24d3b8699191fe).
|
|
||||||
- [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)
|
|
||||||
- [Creation of `ActiveModel::Serialization` from `ActiveModel::Serializer` in Rails (2009)](https://github.com/rails/rails/commit/c6bc8e662614be711f45a8d4b231d5f993b024a7#diff-d029b9768d8df0407a35804a468e3ae5)
|
|
||||||
- [Integration of `ActiveModel::Serializer` into `ActiveRecord::Serialization`](https://github.com/rails/rails/commit/783db25e0c640c1588732967a87d65c10fddc08e)
|
|
||||||
- [Creation of `ActiveModel::Serializer` in Rails (2009)](https://github.com/rails/rails/commit/d2b78b3594b9cc9870e6a6ebfeb2e56d00e6ddb8#diff-80d5beeced9bdc24ca2b04a201543bdd)
|
|
||||||
- [Creation of `ActiveModel::Serializers::JSON` in Rails (2009)](https://github.com/rails/rails/commit/fbdf706fffbfb17731a1f459203d242414ef5086)
|
|
||||||
195
CHANGELOG.md
195
CHANGELOG.md
@ -1,19 +1,196 @@
|
|||||||
## Dev
|
## 0.09.x
|
||||||
|
|
||||||
### [master (unreleased)](https://github.com/rails-api/active_model_serializers/compare/master..dev)
|
### [0-9-stable](https://github.com/rails-api/active_model_serializers/compare/v0.9.7...0-9-stable)
|
||||||
|
|
||||||
Breaking changes:
|
### [v0.9.7 (2017-05-01)](https://github.com/rails-api/active_model_serializers/compare/v0.9.6...v0.9.7)
|
||||||
|
|
||||||
|
- [#2080](https://github.com/rails-api/active_model_serializers/pull/2080) remove `{ payload: nil }` from `!serialize.active_model_serializers` ActiveSupport::Notification. `payload` never had a value. Changes, for example `{ serializer: 'ActiveModel::DefaultSerializer', payload: nil }` to be `{ serializer: 'ActiveModel::DefaultSerializer' }` (@yosiat)
|
||||||
|
|
||||||
|
### [v0.9.6 (2017-01-10)](https://github.com/rails-api/active_model_serializers/compare/v0.9.5...v0.9.6)
|
||||||
|
|
||||||
|
- [#2008](https://github.com/rails-api/active_model_serializers/pull/2008) Fix warning on Thor. (@kirs)
|
||||||
|
|
||||||
|
### [v0.9.5 (2016-03-30)](https://github.com/rails-api/active_model_serializers/compare/v0.9.4...v0.9.5)
|
||||||
|
|
||||||
|
- [#1607](https://github.com/rails-api/active_model_serializers/pull/1607) Merge multiple nested associations. (@Hirtenknogger)
|
||||||
|
|
||||||
|
### [v0.9.4 (2016-01-05)](https://github.com/rails-api/active_model_serializers/compare/v0.9.3...v0.9.4)
|
||||||
|
|
||||||
|
- [#752](https://github.com/rails-api/active_model_serializers/pull/752) Tiny improvement of README 0-9-stable (@basiam)
|
||||||
|
- [#749](https://github.com/rails-api/active_model_serializers/pull/749) remove trailing whitespace (@shwoodard)
|
||||||
|
- [#717](https://github.com/rails-api/active_model_serializers/pull/717) fixed issue with rendering Hash which appears in rails 4.2.0.beta4 (@kurko, @greshny)
|
||||||
|
- [#790](https://github.com/rails-api/active_model_serializers/pull/790) pass context to ArraySerializer (@lanej)
|
||||||
|
- [#797](https://github.com/rails-api/active_model_serializers/pull/797) Fix and test for #490 (@afn)
|
||||||
|
- [#813](https://github.com/rails-api/active_model_serializers/pull/813) Allow to define custom serializer for given class (@jtomaszewski)
|
||||||
|
- [#841](https://github.com/rails-api/active_model_serializers/pull/841) Fix issue with embedding multiple associations under the same root key (@antstorm)
|
||||||
|
- [#748](https://github.com/rails-api/active_model_serializers/pull/748) Propagate serialization_options across associations (@raphaelpereira)
|
||||||
|
|
||||||
|
### [v0.9.3 (2015/01/21 20:29 +00:00)](https://github.com/rails-api/active_model_serializers/compare/v0.9.2...v0.9.3)
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
- [#774](https://github.com/rails-api/active_model_serializers/pull/774) Fix nested include attributes (@nhocki)
|
||||||
|
- [#771](https://github.com/rails-api/active_model_serializers/pull/771) Make linked resource type names consistent with root names (@sweatypitts)
|
||||||
|
- [#696](https://github.com/rails-api/active_model_serializers/pull/696) Explicitly set serializer for associations (@ggordon)
|
||||||
|
- [#700](https://github.com/rails-api/active_model_serializers/pull/700) sparse fieldsets (@arenoir)
|
||||||
|
- [#768](https://github.com/rails-api/active_model_serializers/pull/768) Adds support for `meta` and `meta_key` attribute (@kurko)
|
||||||
|
|
||||||
Fixes:
|
### [v0.9.2](https://github.com/rails-api/active_model_serializers/compare/v0.9.1...v0.9.2)
|
||||||
|
|
||||||
Misc:
|
### [v0.9.1 (2014/12/04 11:54 +00:00)](https://github.com/rails-api/active_model_serializers/compare/v0.9.0...v0.9.1)
|
||||||
|
|
||||||
## [0.10.x](CHANGELOG-0-10.md)
|
- [#707](https://github.com/rails-api/active_model_serializers/pull/707) A Friendly Note on Which AMS Version to Use (@jherdman)
|
||||||
|
- [#730](https://github.com/rails-api/active_model_serializers/pull/730) Fixes nested has_many links in JSONAPI (@kurko)
|
||||||
|
- [#718](https://github.com/rails-api/active_model_serializers/pull/718) Allow overriding the adapter with render option (@ggordon)
|
||||||
|
- [#720](https://github.com/rails-api/active_model_serializers/pull/720) Rename attribute with :key (0.8.x compatibility) (@ggordon)
|
||||||
|
- [#728](https://github.com/rails-api/active_model_serializers/pull/728) Use type as key for linked resources (@kurko)
|
||||||
|
- [#729](https://github.com/rails-api/active_model_serializers/pull/729) Use the new beta build env on Travis (@joshk)
|
||||||
|
- [#703](https://github.com/rails-api/active_model_serializers/pull/703) Support serializer and each_serializer options in renderer (@ggordon, @mieko)
|
||||||
|
- [#727](https://github.com/rails-api/active_model_serializers/pull/727) Includes links inside of linked resources (@kurko)
|
||||||
|
- [#726](https://github.com/rails-api/active_model_serializers/pull/726) Bugfix: include nested has_many associations (@kurko)
|
||||||
|
- [#722](https://github.com/rails-api/active_model_serializers/pull/722) Fix infinite recursion (@ggordon)
|
||||||
|
- [#1](https://github.com/rails-api/active_model_serializers/pull/1) Allow for the implicit use of ArraySerializer when :each_serializer is specified (@mieko)
|
||||||
|
- [#692](https://github.com/rails-api/active_model_serializers/pull/692) Include 'linked' member for json-api collections (@ggordon)
|
||||||
|
- [#714](https://github.com/rails-api/active_model_serializers/pull/714) Define as_json instead of to_json (@guilleiguaran)
|
||||||
|
- [#710](https://github.com/rails-api/active_model_serializers/pull/710) JSON-API: Don't include linked section if associations are empty (@guilleiguaran)
|
||||||
|
- [#711](https://github.com/rails-api/active_model_serializers/pull/711) Fixes rbx gems bundling on TravisCI (@kurko)
|
||||||
|
- [#709](https://github.com/rails-api/active_model_serializers/pull/709) Add type key when association name is different than object type (@guilleiguaran)
|
||||||
|
- [#708](https://github.com/rails-api/active_model_serializers/pull/708) Handle correctly null associations (@guilleiguaran)
|
||||||
|
- [#691](https://github.com/rails-api/active_model_serializers/pull/691) Fix embed option for associations (@jacob-s-son)
|
||||||
|
- [#689](https://github.com/rails-api/active_model_serializers/pull/689) Fix support for custom root in JSON-API adapter (@guilleiguaran)
|
||||||
|
- [#685](https://github.com/rails-api/active_model_serializers/pull/685) Serialize ids as strings in JSON-API adapter (@guilleiguaran)
|
||||||
|
- [#684](https://github.com/rails-api/active_model_serializers/pull/684) Refactor adapters to implement support for array serialization (@guilleiguaran)
|
||||||
|
- [#682](https://github.com/rails-api/active_model_serializers/pull/682) Include root by default in JSON-API serializers (@guilleiguaran)
|
||||||
|
- [#625](https://github.com/rails-api/active_model_serializers/pull/625) Add DSL for urls (@JordanFaust)
|
||||||
|
- [#677](https://github.com/rails-api/active_model_serializers/pull/677) Add support for embed: :ids option for in associations (@guilleiguaran)
|
||||||
|
- [#681](https://github.com/rails-api/active_model_serializers/pull/681) Check superclasses for Serializers (@quainjn)
|
||||||
|
- [#680](https://github.com/rails-api/active_model_serializers/pull/680) Add support for root keys (@NullVoxPopuli)
|
||||||
|
- [#675](https://github.com/rails-api/active_model_serializers/pull/675) Support Rails 4.2.0 (@tricknotes)
|
||||||
|
- [#667](https://github.com/rails-api/active_model_serializers/pull/667) Require only activemodel instead of full rails (@guilleiguaran)
|
||||||
|
- [#653](https://github.com/rails-api/active_model_serializers/pull/653) Add "_test" suffix to JsonApi::HasManyTest filename. (@alexgenco)
|
||||||
|
- [#631](https://github.com/rails-api/active_model_serializers/pull/631) Update build badge URL (@craiglittle)
|
||||||
|
|
||||||
## [0.09.x](CHANGELOG-0-09.md)
|
### [v0.9.0](https://github.com/rails-api/active_model_serializers/compare/v0.9.0.alpha1...v0.9.0)
|
||||||
|
|
||||||
## [0.08.x](CHANGELOG-0-08.md)
|
### [0.9.0.alpha1 - January 7, 2014](https://github.com/rails-api/active_model_serializers/compare/d72b66d4c...v0.9.0.alpha1)
|
||||||
|
|
||||||
## [Prehistory](CHANGELOG-prehistory.md)
|
### 0.9.0.pre
|
||||||
|
|
||||||
|
* The following methods were removed
|
||||||
|
- Model#active\_model\_serializer
|
||||||
|
- Serializer#include!
|
||||||
|
- Serializer#include?
|
||||||
|
- Serializer#attr\_disabled=
|
||||||
|
- Serializer#cache
|
||||||
|
- Serializer#perform\_caching
|
||||||
|
- Serializer#schema (needs more discussion)
|
||||||
|
- Serializer#attribute
|
||||||
|
- Serializer#include\_#{name}? (filter method added)
|
||||||
|
- Serializer#attributes (took a hash)
|
||||||
|
|
||||||
|
* The following things were added
|
||||||
|
- Serializer#filter method
|
||||||
|
- CONFIG object
|
||||||
|
|
||||||
|
* Remove support for ruby 1.8 versions.
|
||||||
|
|
||||||
|
* Require rails >= 3.2.
|
||||||
|
|
||||||
|
* Serializers for associations are being looked up in a parent serializer's namespace first. Same with controllers' namespaces.
|
||||||
|
|
||||||
|
* Added a "prefix" option in case you want to use a different version of serializer.
|
||||||
|
|
||||||
|
* Serializers default namespace can be set in `default_serializer_options` and inherited by associations.
|
||||||
|
|
||||||
|
# VERSION 0.9.0.pre
|
||||||
|
|
||||||
|
* The following methods were removed
|
||||||
|
- Model#active\_model\_serializer
|
||||||
|
- Serializer#include!
|
||||||
|
- Serializer#include?
|
||||||
|
- Serializer#attr\_disabled=
|
||||||
|
- Serializer#cache
|
||||||
|
- Serializer#perform\_caching
|
||||||
|
- Serializer#schema (needs more discussion)
|
||||||
|
- Serializer#attribute
|
||||||
|
- Serializer#include\_#{name}? (filter method added)
|
||||||
|
- Serializer#attributes (took a hash)
|
||||||
|
|
||||||
|
* The following things were added
|
||||||
|
- Serializer#filter method
|
||||||
|
- CONFIG object
|
||||||
|
|
||||||
|
* Remove support for ruby 1.8 versions.
|
||||||
|
|
||||||
|
* Require rails >= 3.2.
|
||||||
|
|
||||||
|
* Serializers for associations are being looked up in a parent serializer's namespace first. Same with controllers' namespaces.
|
||||||
|
|
||||||
|
* Added a "prefix" option in case you want to use a different version of serializer.
|
||||||
|
|
||||||
|
* Serializers default namespace can be set in `default_serializer_options` and inherited by associations.
|
||||||
|
|
||||||
|
# VERSION 0.8.1
|
||||||
|
|
||||||
|
* Fix bug whereby a serializer using 'options' would blow up.
|
||||||
|
|
||||||
|
# VERSION 0.8.0
|
||||||
|
|
||||||
|
* Attributes can now have optional types.
|
||||||
|
|
||||||
|
* A new DefaultSerializer ensures that POROs behave the same way as ActiveModels.
|
||||||
|
|
||||||
|
* If you wish to override ActiveRecord::Base#to\_Json, you can now require
|
||||||
|
'active\_record/serializer\_override'. We don't recommend you do this, but
|
||||||
|
many users do, so we've left it optional.
|
||||||
|
|
||||||
|
* Fixed a bug where ActionController wouldn't always have MimeResponds.
|
||||||
|
|
||||||
|
* An optional caching feature allows you to cache JSON & hashes that AMS uses.
|
||||||
|
Adding 'cached true' to your Serializers will turn on this cache.
|
||||||
|
|
||||||
|
* URL helpers used inside of Engines now work properly.
|
||||||
|
|
||||||
|
* Serializers now can filter attributes with `only` and `except`:
|
||||||
|
|
||||||
|
```
|
||||||
|
UserSerializer.new(user, only: [:first_name, :last_name])
|
||||||
|
UserSerializer.new(user, except: :first_name)
|
||||||
|
```
|
||||||
|
|
||||||
|
* Basic Mongoid support. We now include our mixins in the right place.
|
||||||
|
|
||||||
|
* On Ruby 1.8, we now generate an `id` method that properly serializes `id`
|
||||||
|
columns. See issue #127 for more.
|
||||||
|
|
||||||
|
* Add an alias for `scope` method to be the name of the context. By default
|
||||||
|
this is `current_user`. The name is automatically set when using
|
||||||
|
`serialization_scope` in the controller.
|
||||||
|
|
||||||
|
* Pass through serialization options (such as `:include`) when a model
|
||||||
|
has no serializer defined.
|
||||||
|
|
||||||
|
# VERSION 0.7.0
|
||||||
|
|
||||||
|
* ```embed_key``` option to allow embedding by attributes other than IDs
|
||||||
|
* Fix rendering nil with custom serializer
|
||||||
|
* Fix global ```self.root = false```
|
||||||
|
* Add support for specifying the serializer for an association as a String
|
||||||
|
* Able to specify keys on the attributes method
|
||||||
|
* Serializer Reloading via ActiveSupport::DescendantsTracker
|
||||||
|
* Reduce double map to once; Fixes datamapper eager loading.
|
||||||
|
|
||||||
|
# VERSION 0.6.0
|
||||||
|
|
||||||
|
* Serialize sets properly
|
||||||
|
* Add root option to ArraySerializer
|
||||||
|
* Support polymorphic associations
|
||||||
|
* Support :each_serializer in ArraySerializer
|
||||||
|
* Add `scope` method to easily access the scope in the serializer
|
||||||
|
* Fix regression with Rails 3.2.6; add Rails 4 support
|
||||||
|
* Allow serialization_scope to be disabled with serialization_scope nil
|
||||||
|
* Array serializer should support pure ruby objects besides serializers
|
||||||
|
|
||||||
|
# VERSION 0.5.0
|
||||||
|
|
||||||
|
* First tagged version
|
||||||
|
* Changes generators to always generate an ApplicationSerializer
|
||||||
|
|||||||
@ -1,74 +0,0 @@
|
|||||||
# Contributor Covenant Code of Conduct
|
|
||||||
|
|
||||||
## Our Pledge
|
|
||||||
|
|
||||||
In the interest of fostering an open and welcoming environment, we as
|
|
||||||
contributors and maintainers pledge to making participation in our project and
|
|
||||||
our community a harassment-free experience for everyone, regardless of age, body
|
|
||||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
|
||||||
nationality, personal appearance, race, religion, or sexual identity and
|
|
||||||
orientation.
|
|
||||||
|
|
||||||
## Our Standards
|
|
||||||
|
|
||||||
Examples of behavior that contributes to creating a positive environment
|
|
||||||
include:
|
|
||||||
|
|
||||||
* Using welcoming and inclusive language
|
|
||||||
* Being respectful of differing viewpoints and experiences
|
|
||||||
* Gracefully accepting constructive criticism
|
|
||||||
* Focusing on what is best for the community
|
|
||||||
* Showing empathy towards other community members
|
|
||||||
|
|
||||||
Examples of unacceptable behavior by participants include:
|
|
||||||
|
|
||||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
|
||||||
advances
|
|
||||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
|
||||||
* Public or private harassment
|
|
||||||
* Publishing others' private information, such as a physical or electronic
|
|
||||||
address, without explicit permission
|
|
||||||
* Other conduct which could reasonably be considered inappropriate in a
|
|
||||||
professional setting
|
|
||||||
|
|
||||||
## Our Responsibilities
|
|
||||||
|
|
||||||
Project maintainers are responsible for clarifying the standards of acceptable
|
|
||||||
behavior and are expected to take appropriate and fair corrective action in
|
|
||||||
response to any instances of unacceptable behavior.
|
|
||||||
|
|
||||||
Project maintainers have the right and responsibility to remove, edit, or
|
|
||||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
|
||||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
|
||||||
permanently any contributor for other behaviors that they deem inappropriate,
|
|
||||||
threatening, offensive, or harmful.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
This Code of Conduct applies both within project spaces and in public spaces
|
|
||||||
when an individual is representing the project or its community. Examples of
|
|
||||||
representing a project or community include using an official project e-mail
|
|
||||||
address, posting via an official social media account, or acting as an appointed
|
|
||||||
representative at an online or offline event. Representation of a project may be
|
|
||||||
further defined and clarified by project maintainers.
|
|
||||||
|
|
||||||
## Enforcement
|
|
||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
||||||
reported by contacting one of the owners listed at https://rubygems.org/gems/active_model_serializers. All
|
|
||||||
complaints will be reviewed and investigated and will result in a response that
|
|
||||||
is deemed necessary and appropriate to the circumstances. The project team is
|
|
||||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
|
||||||
Further details of specific enforcement policies may be posted separately.
|
|
||||||
|
|
||||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
|
||||||
faith may face temporary or permanent repercussions as determined by other
|
|
||||||
members of the project's leadership.
|
|
||||||
|
|
||||||
## Attribution
|
|
||||||
|
|
||||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
|
||||||
available at [http://contributor-covenant.org/version/1/4][version]
|
|
||||||
|
|
||||||
[homepage]: http://contributor-covenant.org
|
|
||||||
[version]: http://contributor-covenant.org/version/1/4/
|
|
||||||
104
CONTRIBUTING.md
104
CONTRIBUTING.md
@ -1,100 +1,20 @@
|
|||||||
## Have an issue?
|
Contributing to AMS
|
||||||
|
===================
|
||||||
|
|
||||||
Before opening an issue, try the following:
|
First of all, **thank you**!
|
||||||
|
|
||||||
##### Consult the documentation
|
Now, for the details:
|
||||||
|
|
||||||
See if your issue can be resolved by information in the [documentation](README.md).
|
Please file issues on the [GitHub Issues
|
||||||
|
list](https://github.com/rails-api/active_model_serializers/issues).
|
||||||
|
|
||||||
##### Check for an existing issue
|
Please discuss new features or ask for feedback about a new feature [on
|
||||||
|
rails-api-core](https://groups.google.com/forum/#!forum/rails-api-core).
|
||||||
|
|
||||||
Take a look at the issues to see if a similar one has already been created. If
|
If you want a feature implemented, the best way to get it done is to submit a
|
||||||
one exists, please add any additional information that might expedite
|
pull request that implements it. Tests and docs would be nice.
|
||||||
resolution.
|
|
||||||
|
|
||||||
#### Open an issue
|
Please include a CHANGELOG with all entries that change behavior.
|
||||||
|
|
||||||
If the documentation wasn't able to help resolve the issue and no issue already
|
:heart: :sparkling_heart: :heart:
|
||||||
exists, please open a new issue with the following in mind:
|
|
||||||
|
|
||||||
- Please make sure only to include one issue per report. If you encounter
|
|
||||||
multiple, unrelated issues, please report them as such.
|
|
||||||
- Be detailed. Provide backtraces and example code when possible. Provide
|
|
||||||
information about your environment. e.g., Ruby version, rails version, etc.
|
|
||||||
- Own your issue. Actively participate in the discussion and help drive the
|
|
||||||
issue to closure.
|
|
||||||
- If you resolve your own issue, please share the details on the issue and close
|
|
||||||
it out. Others might have the same issue and sharing solutions is helpful.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
Contributing can be done in many ways and is not exclusive to code. If you have
|
|
||||||
thoughts on a particular issue or feature, we encourage you to open new issues
|
|
||||||
for discussion or add your comments to existing ones.
|
|
||||||
|
|
||||||
#### Pull requests
|
|
||||||
|
|
||||||
We also gladly welcome pull requests. When preparing to work on pull request,
|
|
||||||
please adhere to these standards:
|
|
||||||
|
|
||||||
- Base work on the relevant branch:
|
|
||||||
[0.10-stable](https://github.com/rails-api/active_model_serializers/tree/0-10-stable)
|
|
||||||
or
|
|
||||||
[0.9-stable](https://github.com/rails-api/active_model_serializers/tree/0-9-stable)
|
|
||||||
or
|
|
||||||
[0.8-stable](https://github.com/rails-api/active_model_serializers/tree/0-8-stable)
|
|
||||||
- Squash your commits and regularly rebase off master.
|
|
||||||
- Provide a description of the changes contained in the pull request.
|
|
||||||
- Note any specific areas that should be reviewed.
|
|
||||||
- Include tests.
|
|
||||||
- The test suite must pass on [supported Ruby versions](.travis.yml)
|
|
||||||
- Include updates to the [documentation](docs)
|
|
||||||
where applicable.
|
|
||||||
- Update the
|
|
||||||
[CHANGELOG](CHANGELOG.md)
|
|
||||||
to the appropriate sections with a brief description of the changes.
|
|
||||||
- Do not change the VERSION file.
|
|
||||||
|
|
||||||
#### Running tests
|
|
||||||
|
|
||||||
Run all tests
|
|
||||||
|
|
||||||
`$ rake test`
|
|
||||||
|
|
||||||
Run a single test suite
|
|
||||||
|
|
||||||
`$ rake test TEST=path/to/test.rb`
|
|
||||||
|
|
||||||
Run a single test
|
|
||||||
|
|
||||||
`$ rake test TEST=path/to/test.rb TESTOPTS="--name=test_something"`
|
|
||||||
|
|
||||||
Run tests against different Rails versions by setting the RAILS_VERSION variable
|
|
||||||
and bundling gems. (save this script somewhere executable and run from top of AMS repository)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
rcommand='puts YAML.load_file("./.travis.yml")["env"]["matrix"].join(" ").gsub("RAILS_VERSION=", "")'
|
|
||||||
versions=$(ruby -ryaml -e "$rcommand")
|
|
||||||
|
|
||||||
for version in ${versions[@]}; do
|
|
||||||
export RAILS_VERSION="$version"
|
|
||||||
rm -f Gemfile.lock
|
|
||||||
bundle check || bundle --local || bundle
|
|
||||||
bundle exec rake test
|
|
||||||
if [ "$?" -eq 0 ]; then
|
|
||||||
# green in ANSI
|
|
||||||
echo -e "\033[32m **** Tests passed against Rails ${RAILS_VERSION} **** \033[0m"
|
|
||||||
else
|
|
||||||
# red in ANSI
|
|
||||||
echo -e "\033[31m **** Tests failed against Rails ${RAILS_VERSION} **** \033[0m"
|
|
||||||
read -p '[Enter] any key to continue, [q] to quit...' prompt
|
|
||||||
if [ "$prompt" = 'q' ]; then
|
|
||||||
unset RAILS_VERSION
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
unset RAILS_VERSION
|
|
||||||
done
|
|
||||||
```
|
|
||||||
|
|||||||
586
DESIGN.textile
Normal file
586
DESIGN.textile
Normal file
@ -0,0 +1,586 @@
|
|||||||
|
<strong>This was the original design document for serializers.</strong> It is useful mostly for historical purposes as the public API has changed.
|
||||||
|
|
||||||
|
h2. Rails Serializers
|
||||||
|
|
||||||
|
This guide describes how to use Active Model serializers to build non-trivial JSON services in Rails. By reading this guide, you will learn:
|
||||||
|
|
||||||
|
* When to use the built-in Active Model serialization
|
||||||
|
* When to use a custom serializer for your models
|
||||||
|
* How to use serializers to encapsulate authorization concerns
|
||||||
|
* How to create serializer templates to describe the application-wide structure of your serialized JSON
|
||||||
|
* How to build resources not backed by a single database table for use with JSON services
|
||||||
|
|
||||||
|
This guide covers an intermediate topic and assumes familiarity with Rails conventions. It is suitable for applications that expose a
|
||||||
|
JSON API that may return different results based on the authorization status of the user.
|
||||||
|
|
||||||
|
h3. Serialization
|
||||||
|
|
||||||
|
By default, Active Record objects can serialize themselves into JSON by using the `to_json` method. This method takes a series of additional
|
||||||
|
parameter to control which properties and associations Rails should include in the serialized output.
|
||||||
|
|
||||||
|
When building a web application that uses JavaScript to retrieve JSON data from the server, this mechanism has historically been the primary
|
||||||
|
way that Rails developers prepared their responses. This works great for simple cases, as the logic for serializing an Active Record object
|
||||||
|
is neatly encapsulated in Active Record itself.
|
||||||
|
|
||||||
|
However, this solution quickly falls apart in the face of serialization requirements based on authorization. For instance, a web service
|
||||||
|
may choose to expose additional information about a resource only if the user is entitled to access it. In addition, a JavaScript front-end
|
||||||
|
may want information that is not neatly described in terms of serializing a single Active Record object, or in a different format than.
|
||||||
|
|
||||||
|
In addition, neither the controller nor the model seems like the correct place for logic that describes how to serialize an model object
|
||||||
|
*for the current user*.
|
||||||
|
|
||||||
|
Serializers solve these problems by encapsulating serialization in an object designed for this purpose. If the default +to_json+ semantics,
|
||||||
|
with at most a few configuration options serve your needs, by all means continue to use the built-in +to_json+. If you find yourself doing
|
||||||
|
hash-driven-development in your controllers, juggling authorization logic and other concerns, serializers are for you!
|
||||||
|
|
||||||
|
h3. The Most Basic Serializer
|
||||||
|
|
||||||
|
A basic serializer is a simple Ruby object named after the model class it is serializing.
|
||||||
|
|
||||||
|
<pre lang="ruby">
|
||||||
|
class PostSerializer
|
||||||
|
def initialize(post, scope)
|
||||||
|
@post, @scope = post, scope
|
||||||
|
end
|
||||||
|
|
||||||
|
def as_json
|
||||||
|
{ post: { title: @post.name, body: @post.body } }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
A serializer is initialized with two parameters: the model object it should serialize and an authorization scope. By default, the
|
||||||
|
authorization scope is the current user (+current_user+) but you can use a different object if you want. The serializer also
|
||||||
|
implements an +as_json+ method, which returns a Hash that will be sent to the JSON encoder.
|
||||||
|
|
||||||
|
Rails will transparently use your serializer when you use +render :json+ in your controller.
|
||||||
|
|
||||||
|
<pre lang="ruby">
|
||||||
|
class PostsController < ApplicationController
|
||||||
|
def show
|
||||||
|
@post = Post.find(params[:id])
|
||||||
|
render json: @post
|
||||||
|
end
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Because +respond_with+ uses +render :json+ under the hood for JSON requests, Rails will automatically use your serializer when
|
||||||
|
you use +respond_with+ as well.
|
||||||
|
|
||||||
|
h4. +serializable_hash+
|
||||||
|
|
||||||
|
In general, you will want to implement +serializable_hash+ and +as_json+ to allow serializers to embed associated content
|
||||||
|
directly. The easiest way to implement these two methods is to have +as_json+ call +serializable_hash+ and insert the root.
|
||||||
|
|
||||||
|
<pre lang="ruby">
|
||||||
|
class PostSerializer
|
||||||
|
def initialize(post, scope)
|
||||||
|
@post, @scope = post, scope
|
||||||
|
end
|
||||||
|
|
||||||
|
def serializable_hash
|
||||||
|
{ title: @post.name, body: @post.body }
|
||||||
|
end
|
||||||
|
|
||||||
|
def as_json
|
||||||
|
{ post: serializable_hash }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
h4. Authorization
|
||||||
|
|
||||||
|
Let's update our serializer to include the email address of the author of the post, but only if the current user has superuser
|
||||||
|
access.
|
||||||
|
|
||||||
|
<pre lang="ruby">
|
||||||
|
class PostSerializer
|
||||||
|
def initialize(post, scope)
|
||||||
|
@post, @scope = post, scope
|
||||||
|
end
|
||||||
|
|
||||||
|
def as_json
|
||||||
|
{ post: serializable_hash }
|
||||||
|
end
|
||||||
|
|
||||||
|
def serializable_hash
|
||||||
|
hash = post
|
||||||
|
hash.merge!(super_data) if super?
|
||||||
|
hash
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def post
|
||||||
|
{ title: @post.name, body: @post.body }
|
||||||
|
end
|
||||||
|
|
||||||
|
def super_data
|
||||||
|
{ email: @post.email }
|
||||||
|
end
|
||||||
|
|
||||||
|
def super?
|
||||||
|
@scope.superuser?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
h4. Testing
|
||||||
|
|
||||||
|
One benefit of encapsulating our objects this way is that it becomes extremely straight-forward to test the serialization
|
||||||
|
logic in isolation.
|
||||||
|
|
||||||
|
<pre lang="ruby">
|
||||||
|
require "ostruct"
|
||||||
|
|
||||||
|
class PostSerializerTest < ActiveSupport::TestCase
|
||||||
|
# For now, we use a very simple authorization structure. These tests will need
|
||||||
|
# refactoring if we change that.
|
||||||
|
plebe = OpenStruct.new(super?: false)
|
||||||
|
god = OpenStruct.new(super?: true)
|
||||||
|
|
||||||
|
post = OpenStruct.new(title: "Welcome to my blog!", body: "Blah blah blah", email: "tenderlove@gmail.com")
|
||||||
|
|
||||||
|
test "a regular user sees just the title and body" do
|
||||||
|
json = PostSerializer.new(post, plebe).to_json
|
||||||
|
hash = JSON.parse(json)
|
||||||
|
|
||||||
|
assert_equal post.title, hash.delete("title")
|
||||||
|
assert_equal post.body, hash.delete("body")
|
||||||
|
assert_empty hash
|
||||||
|
end
|
||||||
|
|
||||||
|
test "a superuser sees the title, body and email" do
|
||||||
|
json = PostSerializer.new(post, god).to_json
|
||||||
|
hash = JSON.parse(json)
|
||||||
|
|
||||||
|
assert_equal post.title, hash.delete("title")
|
||||||
|
assert_equal post.body, hash.delete("body")
|
||||||
|
assert_equal post.email, hash.delete("email")
|
||||||
|
assert_empty hash
|
||||||
|
end
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
It's important to note that serializer objects define a clear interface specifically for serializing an existing object.
|
||||||
|
In this case, the serializer expects to receive a post object with +name+, +body+ and +email+ attributes and an authorization
|
||||||
|
scope with a +super?+ method.
|
||||||
|
|
||||||
|
By defining a clear interface, it's must easier to ensure that your authorization logic is behaving correctly. In this case,
|
||||||
|
the serializer doesn't need to concern itself with how the authorization scope decides whether to set the +super?+ flag, just
|
||||||
|
whether it is set. In general, you should document these requirements in your serializer files and programatically via tests.
|
||||||
|
The documentation library +YARD+ provides excellent tools for describing this kind of requirement:
|
||||||
|
|
||||||
|
<pre lang="ruby">
|
||||||
|
class PostSerializer
|
||||||
|
# @param [~body, ~title, ~email] post the post to serialize
|
||||||
|
# @param [~super] scope the authorization scope for this serializer
|
||||||
|
def initialize(post, scope)
|
||||||
|
@post, @scope = post, scope
|
||||||
|
end
|
||||||
|
|
||||||
|
# ...
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
h3. Attribute Sugar
|
||||||
|
|
||||||
|
To simplify this process for a number of common cases, Rails provides a default superclass named +ActiveModel::Serializer+
|
||||||
|
that you can use to implement your serializers.
|
||||||
|
|
||||||
|
For example, you will sometimes want to simply include a number of existing attributes from the source model into the outputted
|
||||||
|
JSON. In the above example, the +title+ and +body+ attributes were always included in the JSON. Let's see how to use
|
||||||
|
+ActiveModel::Serializer+ to simplify our post serializer.
|
||||||
|
|
||||||
|
<pre lang="ruby">
|
||||||
|
class PostSerializer < ActiveModel::Serializer
|
||||||
|
attributes :title, :body
|
||||||
|
|
||||||
|
def serializable_hash
|
||||||
|
hash = attributes
|
||||||
|
hash.merge!(super_data) if super?
|
||||||
|
hash
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def super_data
|
||||||
|
{ email: @post.email }
|
||||||
|
end
|
||||||
|
|
||||||
|
def super?
|
||||||
|
@scope.superuser?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
First, we specified the list of included attributes at the top of the class. This will create an instance method called
|
||||||
|
+attributes+ that extracts those attributes from the post model.
|
||||||
|
|
||||||
|
NOTE: Internally, +ActiveModel::Serializer+ uses +read_attribute_for_serialization+, which defaults to +read_attribute+, which defaults to +send+. So if you're rolling your own models for use with the serializer, you can use simple Ruby accessors for your attributes if you like.
|
||||||
|
|
||||||
|
Next, we use the attributes method in our +serializable_hash+ method, which allowed us to eliminate the +post+ method we hand-rolled
|
||||||
|
earlier. We could also eliminate the +as_json+ method, as +ActiveModel::Serializer+ provides a default +as_json+ method for
|
||||||
|
us that calls our +serializable_hash+ method and inserts a root. But we can go a step further!
|
||||||
|
|
||||||
|
<pre lang="ruby">
|
||||||
|
class PostSerializer < ActiveModel::Serializer
|
||||||
|
attributes :title, :body
|
||||||
|
|
||||||
|
private
|
||||||
|
def attributes
|
||||||
|
hash = super
|
||||||
|
hash.merge!(email: post.email) if super?
|
||||||
|
hash
|
||||||
|
end
|
||||||
|
|
||||||
|
def super?
|
||||||
|
@scope.superuser?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
The superclass provides a default +initialize+ method as well as a default +serializable_hash+ method, which uses
|
||||||
|
+attributes+. We can call +super+ to get the hash based on the attributes we declared, and then add in any additional
|
||||||
|
attributes we want to use.
|
||||||
|
|
||||||
|
NOTE: +ActiveModel::Serializer+ will create an accessor matching the name of the current class for the resource you pass in. In this case, because we have defined a PostSerializer, we can access the resource with the +post+ accessor.
|
||||||
|
|
||||||
|
h3. Associations
|
||||||
|
|
||||||
|
In most JSON APIs, you will want to include associated objects with your serialized object. In this case, let's include
|
||||||
|
the comments with the current post.
|
||||||
|
|
||||||
|
<pre lang="ruby">
|
||||||
|
class PostSerializer < ActiveModel::Serializer
|
||||||
|
attributes :title, :body
|
||||||
|
has_many :comments
|
||||||
|
|
||||||
|
private
|
||||||
|
def attributes
|
||||||
|
hash = super
|
||||||
|
hash.merge!(email: post.email) if super?
|
||||||
|
hash
|
||||||
|
end
|
||||||
|
|
||||||
|
def super?
|
||||||
|
@scope.superuser?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
The default +serializable_hash+ method will include the comments as embedded objects inside the post.
|
||||||
|
|
||||||
|
<pre lang="json">
|
||||||
|
{
|
||||||
|
post: {
|
||||||
|
title: "Hello Blog!",
|
||||||
|
body: "This is my first post. Isn't it fabulous!",
|
||||||
|
comments: [
|
||||||
|
{
|
||||||
|
title: "Awesome",
|
||||||
|
body: "Your first post is great"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Rails uses the same logic to generate embedded serializations as it does when you use +render :json+. In this case,
|
||||||
|
because you didn't define a +CommentSerializer+, Rails used the default +as_json+ on your comment object.
|
||||||
|
|
||||||
|
If you define a serializer, Rails will automatically instantiate it with the existing authorization scope.
|
||||||
|
|
||||||
|
<pre lang="ruby">
|
||||||
|
class CommentSerializer
|
||||||
|
def initialize(comment, scope)
|
||||||
|
@comment, @scope = comment, scope
|
||||||
|
end
|
||||||
|
|
||||||
|
def serializable_hash
|
||||||
|
{ title: @comment.title }
|
||||||
|
end
|
||||||
|
|
||||||
|
def as_json
|
||||||
|
{ comment: serializable_hash }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
If we define the above comment serializer, the outputted JSON will change to:
|
||||||
|
|
||||||
|
<pre lang="json">
|
||||||
|
{
|
||||||
|
post: {
|
||||||
|
title: "Hello Blog!",
|
||||||
|
body: "This is my first post. Isn't it fabulous!",
|
||||||
|
comments: [{ title: "Awesome" }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Let's imagine that our comment system allows an administrator to kill a comment, and we only want to allow
|
||||||
|
users to see the comments they're entitled to see. By default, +has_many :comments+ will simply use the
|
||||||
|
+comments+ accessor on the post object. We can override the +comments+ accessor to limit the comments used
|
||||||
|
to just the comments we want to allow for the current user.
|
||||||
|
|
||||||
|
<pre lang="ruby">
|
||||||
|
class PostSerializer < ActiveModel::Serializer
|
||||||
|
attributes :title. :body
|
||||||
|
has_many :comments
|
||||||
|
|
||||||
|
private
|
||||||
|
def attributes
|
||||||
|
hash = super
|
||||||
|
hash.merge!(email: post.email) if super?
|
||||||
|
hash
|
||||||
|
end
|
||||||
|
|
||||||
|
def comments
|
||||||
|
post.comments_for(scope)
|
||||||
|
end
|
||||||
|
|
||||||
|
def super?
|
||||||
|
@scope.superuser?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
+ActiveModel::Serializer+ will still embed the comments, but this time it will use just the comments
|
||||||
|
for the current user.
|
||||||
|
|
||||||
|
NOTE: The logic for deciding which comments a user should see still belongs in the model layer. In general, you should encapsulate concerns that require making direct Active Record queries in scopes or public methods on your models.
|
||||||
|
|
||||||
|
h4. Modifying Associations
|
||||||
|
|
||||||
|
You can also rename associations if required. Say for example you have an association that
|
||||||
|
makes sense to be named one thing in your code, but another when data is serialized.
|
||||||
|
You can use the <code:key</code> option to specify a different name for an association.
|
||||||
|
Here is an example:
|
||||||
|
|
||||||
|
<pre lang="ruby">
|
||||||
|
class UserSerializer < ActiveModel::Serializer
|
||||||
|
has_many :followed_posts, key: :posts
|
||||||
|
has_one :owned_account, key: :account
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Using the <code>:key</code> without a <code>:serializer</code> option will use implicit detection
|
||||||
|
to determine a serializer. In this example, you'd have to define two classes: <code>PostSerializer</code>
|
||||||
|
and <code>AccountSerializer</code>. You can also add the <code>:serializer</code> option
|
||||||
|
to set it explicitly:
|
||||||
|
|
||||||
|
<pre lang="ruby">
|
||||||
|
class UserSerializer < ActiveModel::Serializer
|
||||||
|
has_many :followed_posts, key: :posts, serializer: CustomPostSerializer
|
||||||
|
has_one :owne_account, key: :account, serializer: PrivateAccountSerializer
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
h3. Customizing Associations
|
||||||
|
|
||||||
|
Not all front-ends expect embedded documents in the same form. In these cases, you can override the
|
||||||
|
default +serializable_hash+, and use conveniences provided by +ActiveModel::Serializer+ to avoid having to
|
||||||
|
build up the hash manually.
|
||||||
|
|
||||||
|
For example, let's say our front-end expects the posts and comments in the following format:
|
||||||
|
|
||||||
|
<pre lang="json">
|
||||||
|
{
|
||||||
|
post: {
|
||||||
|
id: 1
|
||||||
|
title: "Hello Blog!",
|
||||||
|
body: "This is my first post. Isn't it fabulous!",
|
||||||
|
comments: [1,2]
|
||||||
|
},
|
||||||
|
comments: [
|
||||||
|
{
|
||||||
|
id: 1
|
||||||
|
title: "Awesome",
|
||||||
|
body: "Your first post is great"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2
|
||||||
|
title: "Not so awesome",
|
||||||
|
body: "Why is it so short!"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
We could achieve this with a custom +as_json+ method. We will also need to define a serializer for comments.
|
||||||
|
|
||||||
|
<pre lang="ruby">
|
||||||
|
class CommentSerializer < ActiveModel::Serializer
|
||||||
|
attributes :id, :title, :body
|
||||||
|
|
||||||
|
# define any logic for dealing with authorization-based attributes here
|
||||||
|
end
|
||||||
|
|
||||||
|
class PostSerializer < ActiveModel::Serializer
|
||||||
|
attributes :title, :body
|
||||||
|
has_many :comments
|
||||||
|
|
||||||
|
def as_json
|
||||||
|
{ post: serializable_hash }.merge!(associations)
|
||||||
|
end
|
||||||
|
|
||||||
|
def serializable_hash
|
||||||
|
post_hash = attributes
|
||||||
|
post_hash.merge!(association_ids)
|
||||||
|
post_hash
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def attributes
|
||||||
|
hash = super
|
||||||
|
hash.merge!(email: post.email) if super?
|
||||||
|
hash
|
||||||
|
end
|
||||||
|
|
||||||
|
def comments
|
||||||
|
post.comments_for(scope)
|
||||||
|
end
|
||||||
|
|
||||||
|
def super?
|
||||||
|
@scope.superuser?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Here, we used two convenience methods: +associations+ and +association_ids+. The first,
|
||||||
|
+associations+, creates a hash of all of the define associations, using their defined
|
||||||
|
serializers. The second, +association_ids+, generates a hash whose key is the association
|
||||||
|
name and whose value is an Array of the association's keys.
|
||||||
|
|
||||||
|
The +association_ids+ helper will use the overridden version of the association, so in
|
||||||
|
this case, +association_ids+ will only include the ids of the comments provided by the
|
||||||
|
+comments+ method.
|
||||||
|
|
||||||
|
|
||||||
|
h3. Special Association Serializers
|
||||||
|
|
||||||
|
So far, associations defined in serializers use either the +as_json+ method on the model
|
||||||
|
or the defined serializer for the association type. Sometimes, you may want to serialize
|
||||||
|
associated models differently when they are requested as part of another resource than
|
||||||
|
when they are requested on their own.
|
||||||
|
|
||||||
|
For instance, we might want to provide the full comment when it is requested directly,
|
||||||
|
but only its title when requested as part of the post. To achieve this, you can define
|
||||||
|
a serializer for associated objects nested inside the main serializer.
|
||||||
|
|
||||||
|
<pre lang="ruby">
|
||||||
|
class PostSerializer < ActiveModel::Serializer
|
||||||
|
class CommentSerializer < ActiveModel::Serializer
|
||||||
|
attributes :id, :title
|
||||||
|
end
|
||||||
|
|
||||||
|
# same as before
|
||||||
|
# ...
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
In other words, if a +PostSerializer+ is trying to serialize comments, it will first
|
||||||
|
look for +PostSerializer::CommentSerializer+ before falling back to +CommentSerializer+
|
||||||
|
and finally +comment.as_json+.
|
||||||
|
|
||||||
|
h3. Overriding the Defaults
|
||||||
|
|
||||||
|
h4. Authorization Scope
|
||||||
|
|
||||||
|
By default, the authorization scope for serializers is +:current_user+. This means
|
||||||
|
that when you call +render json: @post+, the controller will automatically call
|
||||||
|
its +current_user+ method and pass that along to the serializer's initializer.
|
||||||
|
|
||||||
|
If you want to change that behavior, simply use the +serialization_scope+ class
|
||||||
|
method.
|
||||||
|
|
||||||
|
<pre lang="ruby">
|
||||||
|
class PostsController < ApplicationController
|
||||||
|
serialization_scope :current_app
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
You can also implement an instance method called (no surprise) +serialization_scope+,
|
||||||
|
which allows you to define a dynamic authorization scope based on the current request.
|
||||||
|
|
||||||
|
WARNING: If you use different objects as authorization scopes, make sure that they all implement whatever interface you use in your serializers to control what the outputted JSON looks like.
|
||||||
|
|
||||||
|
h3. Using Serializers Outside of a Request
|
||||||
|
|
||||||
|
The serialization API encapsulates the concern of generating a JSON representation of
|
||||||
|
a particular model for a particular user. As a result, you should be able to easily use
|
||||||
|
serializers, whether you define them yourself or whether you use +ActiveModel::Serializer+
|
||||||
|
outside a request.
|
||||||
|
|
||||||
|
For instance, if you want to generate the JSON representation of a post for a user outside
|
||||||
|
of a request:
|
||||||
|
|
||||||
|
<pre lang="ruby">
|
||||||
|
user = get_user # some logic to get the user in question
|
||||||
|
PostSerializer.new(post, user).to_json # reliably generate JSON output
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
If you want to generate JSON for an anonymous user, you should be able to use whatever
|
||||||
|
technique you use in your application to generate anonymous users outside of a request.
|
||||||
|
Typically, that means creating a new user and not saving it to the database:
|
||||||
|
|
||||||
|
<pre lang="ruby">
|
||||||
|
user = User.new # create a new anonymous user
|
||||||
|
PostSerializer.new(post, user).to_json
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
In general, the better you encapsulate your authorization logic, the more easily you
|
||||||
|
will be able to use the serializer outside of the context of a request. For instance,
|
||||||
|
if you use an authorization library like Cancan, which uses a uniform +user.can?(action, model)+,
|
||||||
|
the authorization interface can very easily be replaced by a plain Ruby object for
|
||||||
|
testing or usage outside the context of a request.
|
||||||
|
|
||||||
|
h3. Collections
|
||||||
|
|
||||||
|
So far, we've talked about serializing individual model objects. By default, Rails
|
||||||
|
will serialize collections, including when using the +associations+ helper, by
|
||||||
|
looping over each element of the collection, calling +serializable_hash+ on the element,
|
||||||
|
and then grouping them by their type (using the plural version of their class name
|
||||||
|
as the root).
|
||||||
|
|
||||||
|
For example, an Array of post objects would serialize as:
|
||||||
|
|
||||||
|
<pre lang="json">
|
||||||
|
{
|
||||||
|
posts: [
|
||||||
|
{
|
||||||
|
title: "FIRST POST!",
|
||||||
|
body: "It's my first pooooost"
|
||||||
|
},
|
||||||
|
{ title: "Second post!",
|
||||||
|
body: "Zomg I made it to my second post"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
If you want to change the behavior of serialized Arrays, you need to create
|
||||||
|
a custom Array serializer.
|
||||||
|
|
||||||
|
<pre lang="ruby">
|
||||||
|
class ArraySerializer < ActiveModel::ArraySerializer
|
||||||
|
def serializable_array
|
||||||
|
serializers.map do |serializer|
|
||||||
|
serializer.serializable_hash
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def as_json
|
||||||
|
hash = { root => serializable_array }
|
||||||
|
hash.merge!(associations)
|
||||||
|
hash
|
||||||
|
end
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
When generating embedded associations using the +associations+ helper inside a
|
||||||
|
regular serializer, it will create a new <code>ArraySerializer</code> with the
|
||||||
|
associated content and call its +serializable_array+ method. In this case, those
|
||||||
|
embedded associations will not recursively include associations.
|
||||||
|
|
||||||
|
When generating an Array using +render json: posts+, the controller will invoke
|
||||||
|
the +as_json+ method, which will include its associations and its root.
|
||||||
61
Gemfile
Normal file
61
Gemfile
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
|
gemspec
|
||||||
|
|
||||||
|
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'
|
||||||
|
gem 'activemodel'
|
||||||
|
gem 'actionpack'
|
||||||
|
gem 'activerecord', group: :test
|
||||||
|
# Rails 5
|
||||||
|
gem 'actionview'
|
||||||
|
end
|
||||||
|
# Rails 5
|
||||||
|
gem 'rails-controller-testing', github: 'rails/rails-controller-testing'
|
||||||
|
else
|
||||||
|
gem_version = "~> #{version}.0"
|
||||||
|
gem 'rails', gem_version
|
||||||
|
gem 'railties', gem_version
|
||||||
|
gem 'activesupport', gem_version
|
||||||
|
gem 'activemodel', gem_version
|
||||||
|
gem 'actionpack', gem_version
|
||||||
|
gem 'activerecord', gem_version, group: :test
|
||||||
|
end
|
||||||
|
|
||||||
|
if RUBY_VERSION < '2'
|
||||||
|
gem 'mime-types', [ '>= 2.6.2', '< 3' ]
|
||||||
|
end
|
||||||
|
|
||||||
|
if RUBY_VERSION < '2.1'
|
||||||
|
gem 'nokogiri', '< 1.7'
|
||||||
|
end
|
||||||
|
|
||||||
|
# https://github.com/bundler/bundler/blob/89a8778c19269561926cea172acdcda241d26d23/lib/bundler/dependency.rb#L30-L54
|
||||||
|
@windows_platforms = [:mswin, :mingw, :x64_mingw]
|
||||||
|
|
||||||
|
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
|
||||||
|
tzinfo_platforms = @windows_platforms
|
||||||
|
tzinfo_platforms += [:jruby] if version >= '4.1'
|
||||||
|
gem 'tzinfo-data', platforms: tzinfo_platforms
|
||||||
|
|
||||||
|
group :bench do
|
||||||
|
gem 'benchmark-ips', '>= 2.7.2'
|
||||||
|
end
|
||||||
|
|
||||||
|
group :test do
|
||||||
|
gem 'sqlite3', platform: (@windows_platforms + [:ruby])
|
||||||
|
gem 'activerecord-jdbcsqlite3-adapter', platform: :jruby
|
||||||
|
|
||||||
|
gem 'simplecov', '~> 0.10', require: false, group: :development
|
||||||
|
end
|
||||||
|
|
||||||
|
group :development, :test do
|
||||||
|
gem 'rubocop', '~> 0.34.0', require: false
|
||||||
|
end
|
||||||
@ -1,6 +1,4 @@
|
|||||||
Copyright (c) 2014 Steve Klabnik
|
Copyright (c) 2011-2012 José Valim & Yehuda Katz
|
||||||
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
@ -20,3 +18,4 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
|||||||
27
Rakefile
27
Rakefile
@ -1,5 +1,24 @@
|
|||||||
begin
|
#!/usr/bin/env rake
|
||||||
require 'bundler/setup'
|
require "bundler/gem_tasks"
|
||||||
rescue LoadError
|
require "rake/testtask"
|
||||||
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
|
||||||
|
desc 'Run tests'
|
||||||
|
test_task = Rake::TestTask.new(:test) do |t|
|
||||||
|
t.libs << 'test'
|
||||||
|
t.pattern = 'test/**/*_test.rb'
|
||||||
|
t.verbose = true
|
||||||
|
end
|
||||||
|
|
||||||
|
task default: :test
|
||||||
|
|
||||||
|
desc 'Run tests in isolated processes'
|
||||||
|
namespace :test do
|
||||||
|
task :isolated do
|
||||||
|
Dir[test_task.pattern].each do |file|
|
||||||
|
cmd = ['ruby']
|
||||||
|
test_task.libs.each { |l| cmd << '-I' << l }
|
||||||
|
cmd << file
|
||||||
|
sh cmd.join(' ')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1,20 +1,26 @@
|
|||||||
# coding: utf-8
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
Gem::Specification.new do |spec|
|
$:.unshift File.expand_path("../lib", __FILE__)
|
||||||
spec.name = 'active_model_serializers'
|
require "active_model/serializer/version"
|
||||||
spec.version = "1.0.0-dev"
|
|
||||||
spec.platform = Gem::Platform::RUBY
|
|
||||||
spec.authors = ['Steve Klabnik']
|
|
||||||
spec.email = ['steve@steveklabnik.com']
|
|
||||||
spec.summary = 'Conventions-based JSON generation for Rails.'
|
|
||||||
spec.description = 'ActiveModel::Serializers allows you to generate your JSON in an object-oriented and convention-driven manner.'
|
|
||||||
spec.homepage = 'https://github.com/rails-api/active_model_serializers'
|
|
||||||
spec.license = 'MIT'
|
|
||||||
|
|
||||||
spec.files = `git ls-files -z`.split("\x0")
|
Gem::Specification.new do |gem|
|
||||||
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
gem.authors = ["José Valim", "Yehuda Katz", "Santiago Pastorino"]
|
||||||
spec.require_paths = ['lib']
|
gem.email = ["jose.valim@gmail.com", "wycats@gmail.com", "santiago@wyeworks.com"]
|
||||||
spec.executables = []
|
gem.description = %q{Making it easy to serialize models for client-side use}
|
||||||
|
gem.summary = %q{Bringing consistency and object orientation to model serialization. Works great for client-side MVC frameworks!}
|
||||||
|
gem.homepage = "https://github.com/rails-api/active_model_serializers"
|
||||||
|
gem.license = 'MIT'
|
||||||
|
|
||||||
spec.required_ruby_version = '>= 2.1'
|
gem.files = Dir['README.md', 'CHANGELOG.md', 'CONTRIBUTING.md', 'DESIGN.textile', 'MIT-LICENSE', 'lib/**/*', 'test/**/*']
|
||||||
|
gem.test_files = Dir['test/**/*']
|
||||||
|
|
||||||
|
gem.name = "active_model_serializers"
|
||||||
|
gem.require_paths = ["lib"]
|
||||||
|
gem.version = ActiveModel::Serializer::VERSION
|
||||||
|
|
||||||
|
gem.required_ruby_version = ">= 1.9.3"
|
||||||
|
|
||||||
|
gem.add_dependency "activemodel", ">= 3.2"
|
||||||
|
gem.add_dependency "concurrent-ruby", "~> 1.0"
|
||||||
|
gem.add_development_dependency "rails", ">= 3.2"
|
||||||
end
|
end
|
||||||
|
|||||||
38
appveyor.yml
38
appveyor.yml
@ -1,11 +1,27 @@
|
|||||||
version: 1.0.{build}-{branch}
|
version: '{build}'
|
||||||
|
|
||||||
skip_tags: true
|
skip_tags: true
|
||||||
|
|
||||||
cache:
|
environment:
|
||||||
- vendor/bundle
|
matrix:
|
||||||
|
- ruby_version: "200"
|
||||||
test_script:
|
- ruby_version: "200-x64"
|
||||||
- true
|
- ruby_version: "21"
|
||||||
|
- ruby_version: "21-x64"
|
||||||
build: off
|
|
||||||
|
cache:
|
||||||
|
- vendor/bundle
|
||||||
|
|
||||||
|
install:
|
||||||
|
- SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
|
||||||
|
- ruby --version
|
||||||
|
- gem --version
|
||||||
|
- gem install bundler
|
||||||
|
- bundler --version
|
||||||
|
- bundle platform
|
||||||
|
- bundle install --path=vendor/bundle --retry=3 --jobs=3
|
||||||
|
|
||||||
|
test_script:
|
||||||
|
- bundle exec rake test
|
||||||
|
|
||||||
|
build: off
|
||||||
|
|||||||
171
bin/bench
Executable file
171
bin/bench
Executable file
@ -0,0 +1,171 @@
|
|||||||
|
#!/usr/bin/env ruby
|
||||||
|
# ActiveModelSerializers Benchmark driver
|
||||||
|
# Adapted from
|
||||||
|
# https://github.com/ruby-bench/ruby-bench-suite/blob/8ad567f7e43a044ae48c36833218423bb1e2bd9d/rails/benchmarks/driver.rb
|
||||||
|
require 'bundler'
|
||||||
|
Bundler.setup
|
||||||
|
require 'json'
|
||||||
|
require 'pathname'
|
||||||
|
require 'optparse'
|
||||||
|
require 'digest'
|
||||||
|
require 'pathname'
|
||||||
|
require 'shellwords'
|
||||||
|
require 'logger'
|
||||||
|
require 'English'
|
||||||
|
|
||||||
|
class BenchmarkDriver
|
||||||
|
ROOT = Pathname File.expand_path(File.join('..', '..'), __FILE__)
|
||||||
|
BASE = ENV.fetch('BASE') { ROOT.join('test', 'benchmark') }
|
||||||
|
ESCAPED_BASE = Shellwords.shellescape(BASE)
|
||||||
|
|
||||||
|
def self.benchmark(options)
|
||||||
|
new(options).run
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.parse_argv_and_run(argv = ARGV, options = {})
|
||||||
|
options = {
|
||||||
|
repeat_count: 1,
|
||||||
|
pattern: [],
|
||||||
|
env: 'CACHE_ON=on'
|
||||||
|
}.merge!(options)
|
||||||
|
|
||||||
|
OptionParser.new do |opts|
|
||||||
|
opts.banner = 'Usage: bin/bench [options]'
|
||||||
|
|
||||||
|
opts.on('-r', '--repeat-count [NUM]', 'Run benchmarks [NUM] times taking the best result') do |value|
|
||||||
|
options[:repeat_count] = value.to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on('-p', '--pattern <PATTERN1,PATTERN2,PATTERN3>', 'Benchmark name pattern') do |value|
|
||||||
|
options[:pattern] = value.split(',')
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on('-e', '--env <var1=val1,var2=val2,var3=vale>', 'ENV variables to pass in') do |value|
|
||||||
|
options[:env] = value.split(',')
|
||||||
|
end
|
||||||
|
end.parse!(argv)
|
||||||
|
|
||||||
|
benchmark(options)
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_reader :commit_hash, :base
|
||||||
|
|
||||||
|
# Based on logfmt:
|
||||||
|
# https://www.brandur.org/logfmt
|
||||||
|
# For more complete implementation see:
|
||||||
|
# see https://github.com/arachnid-cb/logfmtr/blob/master/lib/logfmtr/base.rb
|
||||||
|
# For usage see:
|
||||||
|
# https://blog.codeship.com/logfmt-a-log-format-thats-easy-to-read-and-write/
|
||||||
|
# https://engineering.heroku.com/blogs/2014-09-05-hutils-explore-your-structured-data-logs/
|
||||||
|
# For Ruby parser see:
|
||||||
|
# https://github.com/cyberdelia/logfmt-ruby
|
||||||
|
def self.summary_logger(device = 'output.txt')
|
||||||
|
require 'time'
|
||||||
|
logger = Logger.new(device)
|
||||||
|
logger.level = Logger::INFO
|
||||||
|
logger.formatter = proc { |severity, datetime, progname, msg|
|
||||||
|
msg = "'#{msg}'"
|
||||||
|
"level=#{severity} time=#{datetime.utc.iso8601(6)} pid=#{Process.pid} progname=#{progname} msg=#{msg}#{$INPUT_RECORD_SEPARATOR}"
|
||||||
|
}
|
||||||
|
logger
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.stdout_logger
|
||||||
|
logger = Logger.new(STDOUT)
|
||||||
|
logger.level = Logger::INFO
|
||||||
|
logger.formatter = proc { |_, _, _, msg| "#{msg}#{$INPUT_RECORD_SEPARATOR}" }
|
||||||
|
logger
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(options)
|
||||||
|
@writer = ENV['SUMMARIZE'] ? self.class.summary_logger : self.class.stdout_logger
|
||||||
|
@repeat_count = options[:repeat_count]
|
||||||
|
@pattern = options[:pattern]
|
||||||
|
@commit_hash = options.fetch(:commit_hash) { `git rev-parse --short HEAD`.chomp }
|
||||||
|
@base = options.fetch(:base) { ESCAPED_BASE }
|
||||||
|
@env = Array(options[:env]).join(' ')
|
||||||
|
@rubyopt = options[:rubyopt] # TODO: rename
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
files.each do |path|
|
||||||
|
next if !@pattern.empty? && /#{@pattern.join('|')}/ !~ File.basename(path)
|
||||||
|
run_single(Shellwords.shellescape(path))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def files
|
||||||
|
Dir[File.join(base, 'bm_*')]
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_single(path)
|
||||||
|
script = "RAILS_ENV=production #{@env} ruby #{@rubyopt} #{path}"
|
||||||
|
environment = `ruby -v`.chomp.strip[/\d+\.\d+\.\d+\w+/]
|
||||||
|
|
||||||
|
runs_output = measure(script)
|
||||||
|
if runs_output.empty?
|
||||||
|
results = { error: :no_results }
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
results = {}
|
||||||
|
results['commit_hash'] = commit_hash
|
||||||
|
results['version'] = runs_output.first['version']
|
||||||
|
results['rails_version'] = runs_output.first['rails_version']
|
||||||
|
results['benchmark_run[environment]'] = environment
|
||||||
|
results['runs'] = []
|
||||||
|
|
||||||
|
runs_output.each do |output|
|
||||||
|
results['runs'] << {
|
||||||
|
'benchmark_type[category]' => output['label'],
|
||||||
|
'benchmark_run[result][iterations_per_second]' => output['iterations_per_second'].round(3),
|
||||||
|
'benchmark_run[result][total_allocated_objects_per_iteration]' => output['total_allocated_objects_per_iteration']
|
||||||
|
}
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
results && report(results)
|
||||||
|
end
|
||||||
|
|
||||||
|
def report(results)
|
||||||
|
@writer.info { 'Benchmark results:' }
|
||||||
|
@writer.info { JSON.pretty_generate(results) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def summarize(result)
|
||||||
|
puts "#{result['label']} #{result['iterations_per_second']}/ips; #{result['total_allocated_objects_per_iteration']} objects"
|
||||||
|
end
|
||||||
|
|
||||||
|
# FIXME: ` provides the full output but it'll return failed output as well.
|
||||||
|
def measure(script)
|
||||||
|
results = Hash.new { |h, k| h[k] = [] }
|
||||||
|
|
||||||
|
@repeat_count.times do
|
||||||
|
output = sh(script)
|
||||||
|
output.each_line do |line|
|
||||||
|
next if line.nil?
|
||||||
|
begin
|
||||||
|
result = JSON.parse(line)
|
||||||
|
rescue JSON::ParserError
|
||||||
|
result = { error: line } # rubocop:disable Lint/UselessAssignment
|
||||||
|
else
|
||||||
|
summarize(result)
|
||||||
|
results[result['label']] << result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
results.map do |_, bm_runs|
|
||||||
|
bm_runs.sort_by do |run|
|
||||||
|
run['iterations_per_second']
|
||||||
|
end.last
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def sh(cmd)
|
||||||
|
`#{cmd}`
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
BenchmarkDriver.parse_argv_and_run if $PROGRAM_NAME == __FILE__
|
||||||
@ -1,15 +0,0 @@
|
|||||||
- Start Date: (YYYY-MM-DD)
|
|
||||||
- RFC PR: https://github.com/rails-api/active_model_serializers/pull/dddd
|
|
||||||
- ActiveModelSerializers Issue: https://github.com/rails-api/active_model_serializers/issues/dddd
|
|
||||||
|
|
||||||
# Summary
|
|
||||||
|
|
||||||
# Motivation
|
|
||||||
|
|
||||||
# Detailed design
|
|
||||||
|
|
||||||
# Drawbacks
|
|
||||||
|
|
||||||
# Alternatives
|
|
||||||
|
|
||||||
# Unresolved questions
|
|
||||||
99
lib/action_controller/serialization.rb
Normal file
99
lib/action_controller/serialization.rb
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
require 'active_support/core_ext/class/attribute'
|
||||||
|
|
||||||
|
module ActionController
|
||||||
|
# Action Controller Serialization
|
||||||
|
#
|
||||||
|
# Overrides render :json to check if the given object implements +active_model_serializer+
|
||||||
|
# as a method. If so, use the returned serializer instead of calling +to_json+ on the object.
|
||||||
|
#
|
||||||
|
# This module also provides a serialization_scope method that allows you to configure the
|
||||||
|
# +serialization_scope+ of the serializer. Most apps will likely set the +serialization_scope+
|
||||||
|
# to the current user:
|
||||||
|
#
|
||||||
|
# class ApplicationController < ActionController::Base
|
||||||
|
# serialization_scope :current_user
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# If you need more complex scope rules, you can simply override the serialization_scope:
|
||||||
|
#
|
||||||
|
# class ApplicationController < ActionController::Base
|
||||||
|
# private
|
||||||
|
#
|
||||||
|
# def serialization_scope
|
||||||
|
# current_user
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
module Serialization
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
include ActionController::Renderers
|
||||||
|
|
||||||
|
class << self
|
||||||
|
attr_accessor :enabled
|
||||||
|
end
|
||||||
|
self.enabled = true
|
||||||
|
|
||||||
|
included do
|
||||||
|
class_attribute :_serialization_scope
|
||||||
|
self._serialization_scope = :current_user
|
||||||
|
end
|
||||||
|
|
||||||
|
module ClassMethods
|
||||||
|
def serialization_scope(scope)
|
||||||
|
self._serialization_scope = scope
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
[:_render_option_json, :_render_with_renderer_json].each do |renderer_method|
|
||||||
|
define_method renderer_method do |resource, options|
|
||||||
|
serializer = build_json_serializer(resource, options)
|
||||||
|
|
||||||
|
if serializer
|
||||||
|
super(serializer, options)
|
||||||
|
else
|
||||||
|
super(resource, options)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def namespace_for_serializer
|
||||||
|
@namespace_for_serializer ||= self.class.parent unless self.class.parent == Object
|
||||||
|
end
|
||||||
|
|
||||||
|
def default_serializer(resource)
|
||||||
|
options = {}.tap do |o|
|
||||||
|
o[:namespace] = namespace_for_serializer if namespace_for_serializer
|
||||||
|
end
|
||||||
|
|
||||||
|
ActiveModel::Serializer.serializer_for(resource, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def default_serializer_options
|
||||||
|
{}
|
||||||
|
end
|
||||||
|
|
||||||
|
def serialization_scope
|
||||||
|
_serialization_scope = self.class._serialization_scope
|
||||||
|
send(_serialization_scope) if _serialization_scope && respond_to?(_serialization_scope, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_json_serializer(resource, options = {})
|
||||||
|
options = default_serializer_options.merge(options)
|
||||||
|
@namespace_for_serializer = options.fetch(:namespace, nil)
|
||||||
|
|
||||||
|
if serializer = options.fetch(:serializer, default_serializer(resource))
|
||||||
|
options[:scope] = serialization_scope unless options.has_key?(:scope)
|
||||||
|
|
||||||
|
if resource.respond_to?(:to_ary)
|
||||||
|
options[:resource_name] = controller_name
|
||||||
|
options[:namespace] = namespace_for_serializer if namespace_for_serializer
|
||||||
|
end
|
||||||
|
|
||||||
|
serializer.new(resource, options)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
79
lib/action_controller/serialization_test_case.rb
Normal file
79
lib/action_controller/serialization_test_case.rb
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
module ActionController
|
||||||
|
module SerializationAssertions
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
setup :setup_serialization_subscriptions
|
||||||
|
teardown :teardown_serialization_subscriptions
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup_serialization_subscriptions
|
||||||
|
@serializers = Hash.new(0)
|
||||||
|
|
||||||
|
ActiveSupport::Notifications.subscribe("!serialize.active_model_serializers") do |name, start, finish, id, payload|
|
||||||
|
serializer = payload[:serializer]
|
||||||
|
@serializers[serializer] += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown_serialization_subscriptions
|
||||||
|
ActiveSupport::Notifications.unsubscribe("!serialize.active_model_serializers")
|
||||||
|
end
|
||||||
|
|
||||||
|
def process(*args)
|
||||||
|
@serializers = Hash.new(0)
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
# Asserts that the request was rendered with the appropriate serializers.
|
||||||
|
#
|
||||||
|
# # assert that the "PostSerializer" serializer was rendered
|
||||||
|
# assert_serializer "PostSerializer"
|
||||||
|
#
|
||||||
|
# # assert that the instance of PostSerializer was rendered
|
||||||
|
# assert_serializer PostSerializer
|
||||||
|
#
|
||||||
|
# # assert that the "PostSerializer" serializer was rendered
|
||||||
|
# assert_serializer :post_serializer
|
||||||
|
#
|
||||||
|
# # assert that the rendered serializer starts with "Post"
|
||||||
|
# assert_serializer %r{\APost.+\Z}
|
||||||
|
#
|
||||||
|
# # assert that no serializer was rendered
|
||||||
|
# assert_serializer nil
|
||||||
|
#
|
||||||
|
#
|
||||||
|
def assert_serializer(options = {}, message = nil)
|
||||||
|
# Force body to be read in case the template is being streamed.
|
||||||
|
response.body
|
||||||
|
|
||||||
|
rendered = @serializers
|
||||||
|
msg = message || "expecting <#{options.inspect}> but rendering with <#{rendered.keys}>"
|
||||||
|
|
||||||
|
matches_serializer = case options
|
||||||
|
when lambda { |options| options.kind_of?(Class) && options < ActiveModel::Serializer }
|
||||||
|
rendered.any? do |serializer, count|
|
||||||
|
options.name == serializer
|
||||||
|
end
|
||||||
|
when Symbol
|
||||||
|
options = options.to_s.camelize
|
||||||
|
rendered.any? do |serializer, count|
|
||||||
|
serializer == options
|
||||||
|
end
|
||||||
|
when String
|
||||||
|
!options.empty? && rendered.any? do |serializer, count|
|
||||||
|
serializer == options
|
||||||
|
end
|
||||||
|
when Regexp
|
||||||
|
rendered.any? do |serializer, count|
|
||||||
|
serializer.match(options)
|
||||||
|
end
|
||||||
|
when NilClass
|
||||||
|
rendered.blank?
|
||||||
|
else
|
||||||
|
raise ArgumentError, "assert_serializer only accepts a String, Symbol, Regexp, ActiveModel::Serializer, or nil"
|
||||||
|
end
|
||||||
|
assert matches_serializer, msg
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
68
lib/active_model/array_serializer.rb
Normal file
68
lib/active_model/array_serializer.rb
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
require 'active_model/default_serializer'
|
||||||
|
require 'active_model/serializable'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class ArraySerializer
|
||||||
|
include Serializable
|
||||||
|
|
||||||
|
class << self
|
||||||
|
attr_accessor :_root
|
||||||
|
alias root _root=
|
||||||
|
alias root= _root=
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(object, options={})
|
||||||
|
@object = object
|
||||||
|
@scope = options[:scope]
|
||||||
|
@root = options.fetch(:root, self.class._root)
|
||||||
|
@polymorphic = options.fetch(:polymorphic, false)
|
||||||
|
@meta_key = options[:meta_key] || :meta
|
||||||
|
@meta = options[@meta_key]
|
||||||
|
@each_serializer = options[:each_serializer]
|
||||||
|
@resource_name = options[:resource_name]
|
||||||
|
@only = options[:only] ? Array(options[:only]) : nil
|
||||||
|
@except = options[:except] ? Array(options[:except]) : nil
|
||||||
|
@context = options[:context]
|
||||||
|
@namespace = options[:namespace]
|
||||||
|
@key_format = options[:key_format] || options[:each_serializer].try(:key_format)
|
||||||
|
end
|
||||||
|
attr_accessor :object, :scope, :root, :meta_key, :meta, :key_format, :context
|
||||||
|
|
||||||
|
def json_key
|
||||||
|
key = root.nil? ? @resource_name : root
|
||||||
|
|
||||||
|
key_format == :lower_camel && key.present? ? key.camelize(:lower) : key
|
||||||
|
end
|
||||||
|
|
||||||
|
def serializer_for(item)
|
||||||
|
serializer_class = @each_serializer || Serializer.serializer_for(item, namespace: @namespace) || DefaultSerializer
|
||||||
|
serializer_class.new(item, scope: scope, key_format: key_format, context: @context, only: @only, except: @except, polymorphic: @polymorphic, namespace: @namespace)
|
||||||
|
end
|
||||||
|
|
||||||
|
def serializable_object(options={})
|
||||||
|
@object.map do |item|
|
||||||
|
serializer_for(item).serializable_object_with_notification(options)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
alias_method :serializable_array, :serializable_object
|
||||||
|
|
||||||
|
def embedded_in_root_associations
|
||||||
|
@object.each_with_object({}) do |item, hash|
|
||||||
|
serializer_for(item).embedded_in_root_associations.each_pair do |type, objects|
|
||||||
|
next if !objects || objects.flatten.empty?
|
||||||
|
|
||||||
|
if hash.has_key?(type)
|
||||||
|
case hash[type] when Hash
|
||||||
|
hash[type].deep_merge!(objects){ |key, old, new| (Array(old) + Array(new)).uniq }
|
||||||
|
else
|
||||||
|
hash[type].concat(objects).uniq!
|
||||||
|
end
|
||||||
|
else
|
||||||
|
hash[type] = objects
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
28
lib/active_model/default_serializer.rb
Normal file
28
lib/active_model/default_serializer.rb
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
require 'active_model/serializable'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
# DefaultSerializer
|
||||||
|
#
|
||||||
|
# Provides a constant interface for all items
|
||||||
|
class DefaultSerializer
|
||||||
|
include ActiveModel::Serializable
|
||||||
|
|
||||||
|
attr_reader :object
|
||||||
|
|
||||||
|
def initialize(object, options={})
|
||||||
|
@object = object
|
||||||
|
@wrap_in_array = options[:_wrap_in_array]
|
||||||
|
end
|
||||||
|
|
||||||
|
def as_json(options={})
|
||||||
|
instrument do
|
||||||
|
return [] if @object.nil? && @wrap_in_array
|
||||||
|
hash = @object.as_json
|
||||||
|
@wrap_in_array ? [hash] : hash
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
alias serializable_hash as_json
|
||||||
|
alias serializable_object as_json
|
||||||
|
end
|
||||||
|
end
|
||||||
59
lib/active_model/serializable.rb
Normal file
59
lib/active_model/serializable.rb
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
require 'active_model/serializable/utils'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
module Serializable
|
||||||
|
INSTRUMENTATION_KEY = '!serialize.active_model_serializers'.freeze
|
||||||
|
|
||||||
|
def self.included(base)
|
||||||
|
base.extend Utils
|
||||||
|
end
|
||||||
|
|
||||||
|
def as_json(options={})
|
||||||
|
instrument do
|
||||||
|
if root = options.fetch(:root, json_key)
|
||||||
|
hash = { root => serializable_object(options) }
|
||||||
|
hash.merge!(serializable_data)
|
||||||
|
hash
|
||||||
|
else
|
||||||
|
serializable_object(options)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def serializable_object_with_notification(options={})
|
||||||
|
instrument { serializable_object(options) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def serializable_data
|
||||||
|
embedded_in_root_associations.tap do |hash|
|
||||||
|
if respond_to?(:meta) && meta
|
||||||
|
hash[meta_key] = meta
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def namespace
|
||||||
|
if module_name = get_namespace
|
||||||
|
Serializer.serializers_cache.fetch_or_store(module_name) do
|
||||||
|
Utils._const_get(module_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def embedded_in_root_associations
|
||||||
|
{}
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def get_namespace
|
||||||
|
modules = self.class.name.split('::')
|
||||||
|
modules[0..-2].join('::') if modules.size > 1
|
||||||
|
end
|
||||||
|
|
||||||
|
def instrument(&block)
|
||||||
|
payload = { serializer: self.class.name }
|
||||||
|
ActiveSupport::Notifications.instrument(INSTRUMENTATION_KEY, payload, &block)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
16
lib/active_model/serializable/utils.rb
Normal file
16
lib/active_model/serializable/utils.rb
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
module ActiveModel
|
||||||
|
module Serializable
|
||||||
|
module Utils
|
||||||
|
extend self
|
||||||
|
|
||||||
|
def _const_get(const)
|
||||||
|
begin
|
||||||
|
method = RUBY_VERSION >= '2.0' ? :const_get : :qualified_const_get
|
||||||
|
Object.send method, const
|
||||||
|
rescue NameError
|
||||||
|
const.safe_constantize
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
318
lib/active_model/serializer.rb
Normal file
318
lib/active_model/serializer.rb
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
require 'active_model/array_serializer'
|
||||||
|
require 'active_model/serializable'
|
||||||
|
require 'active_model/serializer/association'
|
||||||
|
require 'active_model/serializer/config'
|
||||||
|
|
||||||
|
require 'thread'
|
||||||
|
require 'concurrent/map'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
include Serializable
|
||||||
|
|
||||||
|
@mutex = Mutex.new
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def inherited(base)
|
||||||
|
base._root = _root
|
||||||
|
base._attributes = (_attributes || []).dup
|
||||||
|
base._associations = (_associations || {}).dup
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup
|
||||||
|
@mutex.synchronize do
|
||||||
|
yield CONFIG
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
EMBED_IN_ROOT_OPTIONS = [
|
||||||
|
:include,
|
||||||
|
:embed_in_root,
|
||||||
|
:embed_in_root_key,
|
||||||
|
:embed_namespace
|
||||||
|
].freeze
|
||||||
|
|
||||||
|
def embed(type, options={})
|
||||||
|
CONFIG.embed = type
|
||||||
|
if EMBED_IN_ROOT_OPTIONS.any? { |opt| options[opt].present? }
|
||||||
|
CONFIG.embed_in_root = true
|
||||||
|
end
|
||||||
|
if options[:embed_in_root_key].present?
|
||||||
|
CONFIG.embed_in_root_key = options[:embed_in_root_key]
|
||||||
|
end
|
||||||
|
ActiveSupport::Deprecation.warn <<-WARN
|
||||||
|
** Notice: embed is deprecated. **
|
||||||
|
The use of .embed method on a Serializer will be soon removed, as this should have a global scope and not a class scope.
|
||||||
|
Please use the global .setup method instead:
|
||||||
|
ActiveModel::Serializer.setup do |config|
|
||||||
|
config.embed = :#{type}
|
||||||
|
config.embed_in_root = #{CONFIG.embed_in_root || false}
|
||||||
|
end
|
||||||
|
WARN
|
||||||
|
end
|
||||||
|
|
||||||
|
def format_keys(format)
|
||||||
|
@key_format = format
|
||||||
|
end
|
||||||
|
attr_reader :key_format
|
||||||
|
|
||||||
|
def serializer_for(resource, options = {})
|
||||||
|
if resource.respond_to?(:serializer_class)
|
||||||
|
resource.serializer_class
|
||||||
|
elsif resource.respond_to?(:to_ary)
|
||||||
|
if Object.constants.include?(:ArraySerializer)
|
||||||
|
::ArraySerializer
|
||||||
|
else
|
||||||
|
ArraySerializer
|
||||||
|
end
|
||||||
|
else
|
||||||
|
klass_name = build_serializer_class(resource, options)
|
||||||
|
Serializer.serializers_cache.fetch_or_store(klass_name) do
|
||||||
|
_const_get(klass_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_accessor :_root, :_attributes, :_associations
|
||||||
|
alias root _root=
|
||||||
|
alias root= _root=
|
||||||
|
|
||||||
|
def root_name
|
||||||
|
if name
|
||||||
|
root_name = name.demodulize.underscore.sub(/_serializer$/, '')
|
||||||
|
CONFIG.plural_default_root ? root_name.pluralize : root_name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def attributes(*attrs)
|
||||||
|
attrs.each do |attr|
|
||||||
|
striped_attr = strip_attribute attr
|
||||||
|
|
||||||
|
@_attributes << striped_attr
|
||||||
|
|
||||||
|
define_method striped_attr do
|
||||||
|
object.read_attribute_for_serialization attr
|
||||||
|
end unless method_defined?(attr)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_one(*attrs)
|
||||||
|
associate(Association::HasOne, *attrs)
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_many(*attrs)
|
||||||
|
associate(Association::HasMany, *attrs)
|
||||||
|
end
|
||||||
|
|
||||||
|
def serializers_cache
|
||||||
|
@serializers_cache ||= Concurrent::Map.new
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def strip_attribute(attr)
|
||||||
|
symbolized = attr.is_a?(Symbol)
|
||||||
|
|
||||||
|
attr = attr.to_s.gsub(/\?\Z/, '')
|
||||||
|
attr = attr.to_sym if symbolized
|
||||||
|
attr
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_serializer_class(resource, options)
|
||||||
|
"".tap do |klass_name|
|
||||||
|
klass_name << "#{options[:namespace]}::" if options[:namespace]
|
||||||
|
klass_name << options[:prefix].to_s.classify if options[:prefix]
|
||||||
|
klass_name << "#{resource.class.name}Serializer"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def associate(klass, *attrs)
|
||||||
|
options = attrs.extract_options!
|
||||||
|
|
||||||
|
attrs.each do |attr|
|
||||||
|
define_method attr do
|
||||||
|
object.send attr
|
||||||
|
end unless method_defined?(attr)
|
||||||
|
|
||||||
|
@_associations[attr] = klass.new(attr, options)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(object, options={})
|
||||||
|
@object = object
|
||||||
|
@scope = options[:scope]
|
||||||
|
@root = options.fetch(:root, self.class._root)
|
||||||
|
@polymorphic = options.fetch(:polymorphic, false)
|
||||||
|
@meta_key = options[:meta_key] || :meta
|
||||||
|
@meta = options[@meta_key]
|
||||||
|
@wrap_in_array = options[:_wrap_in_array]
|
||||||
|
@only = options[:only] ? Array(options[:only]) : nil
|
||||||
|
@except = options[:except] ? Array(options[:except]) : nil
|
||||||
|
@key_format = options[:key_format]
|
||||||
|
@context = options[:context]
|
||||||
|
@namespace = options[:namespace]
|
||||||
|
end
|
||||||
|
attr_accessor :object, :scope, :root, :meta_key, :meta, :key_format, :context, :polymorphic
|
||||||
|
|
||||||
|
def json_key
|
||||||
|
key = if root == true || root.nil?
|
||||||
|
self.class.root_name
|
||||||
|
else
|
||||||
|
root
|
||||||
|
end
|
||||||
|
|
||||||
|
key_format == :lower_camel && key.present? ? key.camelize(:lower) : key
|
||||||
|
end
|
||||||
|
|
||||||
|
def attributes
|
||||||
|
filter(self.class._attributes.dup).each_with_object({}) do |name, hash|
|
||||||
|
hash[name] = send(name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def associations(options={})
|
||||||
|
associations = self.class._associations
|
||||||
|
included_associations = filter(associations.keys)
|
||||||
|
associations.each_with_object({}) do |(name, association), hash|
|
||||||
|
if included_associations.include? name
|
||||||
|
if association.embed_ids?
|
||||||
|
ids = serialize_ids association
|
||||||
|
if association.embed_namespace?
|
||||||
|
hash = hash[association.embed_namespace] ||= {}
|
||||||
|
hash[association.key] = ids
|
||||||
|
else
|
||||||
|
hash[association.key] = ids
|
||||||
|
end
|
||||||
|
elsif association.embed_objects?
|
||||||
|
if association.embed_namespace?
|
||||||
|
hash = hash[association.embed_namespace] ||= {}
|
||||||
|
end
|
||||||
|
hash[association.embedded_key] = serialize association, options
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def filter(keys)
|
||||||
|
if @only
|
||||||
|
keys & @only
|
||||||
|
elsif @except
|
||||||
|
keys - @except
|
||||||
|
else
|
||||||
|
keys
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def embedded_in_root_associations
|
||||||
|
associations = self.class._associations
|
||||||
|
included_associations = filter(associations.keys)
|
||||||
|
associations.each_with_object({}) do |(name, association), hash|
|
||||||
|
if included_associations.include? name
|
||||||
|
association_serializer = build_serializer(association)
|
||||||
|
# we must do this always because even if the current association is not
|
||||||
|
# embedded in root, it might have its own associations that are embedded in root
|
||||||
|
hash.merge!(association_serializer.embedded_in_root_associations) do |key, oldval, newval|
|
||||||
|
if oldval.respond_to?(:to_ary)
|
||||||
|
[oldval, newval].flatten.uniq
|
||||||
|
else
|
||||||
|
oldval.merge(newval) { |_, oldval, newval| [oldval, newval].flatten.uniq }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if association.embed_in_root?
|
||||||
|
if association.embed_in_root_key?
|
||||||
|
hash = hash[association.embed_in_root_key] ||= {}
|
||||||
|
end
|
||||||
|
|
||||||
|
serialized_data = association_serializer.serializable_object
|
||||||
|
key = association.root_key
|
||||||
|
if hash.has_key?(key)
|
||||||
|
hash[key].concat(serialized_data).uniq!
|
||||||
|
else
|
||||||
|
hash[key] = serialized_data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_serializer(association)
|
||||||
|
object = send(association.name)
|
||||||
|
association.build_serializer(object, association_options_for_serializer(association))
|
||||||
|
end
|
||||||
|
|
||||||
|
def association_options_for_serializer(association)
|
||||||
|
prefix = association.options[:prefix]
|
||||||
|
namespace = association.options[:namespace] || @namespace || self.namespace
|
||||||
|
|
||||||
|
{ scope: scope }.tap do |opts|
|
||||||
|
opts[:namespace] = namespace if namespace
|
||||||
|
opts[:prefix] = prefix if prefix
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def serialize(association,options={})
|
||||||
|
build_serializer(association).serializable_object(options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def serialize_ids(association)
|
||||||
|
associated_data = send(association.name)
|
||||||
|
if associated_data.respond_to?(:to_ary)
|
||||||
|
associated_data.map { |elem| serialize_id(elem, association) }
|
||||||
|
else
|
||||||
|
serialize_id(associated_data, association) if associated_data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def key_format
|
||||||
|
@key_format || self.class.key_format || CONFIG.key_format
|
||||||
|
end
|
||||||
|
|
||||||
|
def format_key(key)
|
||||||
|
if key_format == :lower_camel
|
||||||
|
key.to_s.camelize(:lower)
|
||||||
|
else
|
||||||
|
key
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def convert_keys(hash)
|
||||||
|
Hash[hash.map do |k,v|
|
||||||
|
key = if k.is_a?(Symbol)
|
||||||
|
format_key(k).to_sym
|
||||||
|
else
|
||||||
|
format_key(k)
|
||||||
|
end
|
||||||
|
|
||||||
|
[key ,v]
|
||||||
|
end]
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_writer :serialization_options
|
||||||
|
def serialization_options
|
||||||
|
@serialization_options || {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def serializable_object(options={})
|
||||||
|
self.serialization_options = options
|
||||||
|
return @wrap_in_array ? [] : nil if @object.nil?
|
||||||
|
hash = attributes
|
||||||
|
hash.merge! associations(options)
|
||||||
|
hash = convert_keys(hash) if key_format.present?
|
||||||
|
hash = { :type => type_name(@object), type_name(@object) => hash } if @polymorphic
|
||||||
|
@wrap_in_array ? [hash] : hash
|
||||||
|
end
|
||||||
|
alias_method :serializable_hash, :serializable_object
|
||||||
|
|
||||||
|
def serialize_id(elem, association)
|
||||||
|
id = elem.read_attribute_for_serialization(association.embed_key)
|
||||||
|
association.polymorphic? ? { id: id, type: type_name(elem) } : id
|
||||||
|
end
|
||||||
|
|
||||||
|
def type_name(elem)
|
||||||
|
elem.class.to_s.demodulize.underscore.to_sym
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
58
lib/active_model/serializer/association.rb
Normal file
58
lib/active_model/serializer/association.rb
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
require 'active_model/default_serializer'
|
||||||
|
require 'active_model/serializer/association/has_one'
|
||||||
|
require 'active_model/serializer/association/has_many'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class Association
|
||||||
|
def initialize(name, options={})
|
||||||
|
if options.has_key?(:include)
|
||||||
|
ActiveSupport::Deprecation.warn <<-WARN
|
||||||
|
** Notice: include was renamed to embed_in_root. **
|
||||||
|
WARN
|
||||||
|
end
|
||||||
|
|
||||||
|
@name = name.to_s
|
||||||
|
@options = options
|
||||||
|
self.embed = options.fetch(:embed) { CONFIG.embed }
|
||||||
|
@polymorphic = options.fetch(:polymorphic, false)
|
||||||
|
@embed_in_root = options.fetch(:embed_in_root) { options.fetch(:include) { CONFIG.embed_in_root } }
|
||||||
|
@key_format = options.fetch(:key_format) { CONFIG.key_format }
|
||||||
|
@embed_key = options[:embed_key] || :id
|
||||||
|
@key = options[:key]
|
||||||
|
@embedded_key = options[:root] || name
|
||||||
|
@embed_in_root_key = options.fetch(:embed_in_root_key) { CONFIG.embed_in_root_key }
|
||||||
|
@embed_namespace = options.fetch(:embed_namespace) { CONFIG.embed_namespace }
|
||||||
|
|
||||||
|
serializer = @options[:serializer]
|
||||||
|
@serializer_from_options = serializer.is_a?(String) ? serializer.constantize : serializer
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_reader :name, :embed_ids, :embed_objects, :polymorphic
|
||||||
|
attr_accessor :embed_in_root, :embed_key, :key, :embedded_key, :root_key, :serializer_from_options, :options, :key_format, :embed_in_root_key, :embed_namespace
|
||||||
|
alias embed_ids? embed_ids
|
||||||
|
alias embed_objects? embed_objects
|
||||||
|
alias embed_in_root? embed_in_root
|
||||||
|
alias embed_in_root_key? embed_in_root_key
|
||||||
|
alias embed_namespace? embed_namespace
|
||||||
|
alias polymorphic? polymorphic
|
||||||
|
|
||||||
|
def embed=(embed)
|
||||||
|
@embed_ids = embed == :id || embed == :ids
|
||||||
|
@embed_objects = embed == :object || embed == :objects
|
||||||
|
end
|
||||||
|
|
||||||
|
def serializer_from_object(object, options = {})
|
||||||
|
Serializer.serializer_for(object, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def default_serializer
|
||||||
|
DefaultSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_serializer(object, options = {})
|
||||||
|
serializer_class(object, options).new(object, options.merge(self.options))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
39
lib/active_model/serializer/association/has_many.rb
Normal file
39
lib/active_model/serializer/association/has_many.rb
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class Association
|
||||||
|
class HasMany < Association
|
||||||
|
def initialize(name, *args)
|
||||||
|
super
|
||||||
|
@root_key = @embedded_key.to_s
|
||||||
|
@key ||= case CONFIG.default_key_type
|
||||||
|
when :name then name.to_s.pluralize
|
||||||
|
else "#{name.to_s.singularize}_ids"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def serializer_class(object, _)
|
||||||
|
if use_array_serializer?
|
||||||
|
ArraySerializer
|
||||||
|
else
|
||||||
|
serializer_from_options
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def options
|
||||||
|
if use_array_serializer?
|
||||||
|
{ each_serializer: serializer_from_options }.merge! super
|
||||||
|
else
|
||||||
|
super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def use_array_serializer?
|
||||||
|
!serializer_from_options ||
|
||||||
|
serializer_from_options && !(serializer_from_options <= ArraySerializer)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
25
lib/active_model/serializer/association/has_one.rb
Normal file
25
lib/active_model/serializer/association/has_one.rb
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class Association
|
||||||
|
class HasOne < Association
|
||||||
|
def initialize(name, *args)
|
||||||
|
super
|
||||||
|
@root_key = @embedded_key.to_s.pluralize
|
||||||
|
@key ||= case CONFIG.default_key_type
|
||||||
|
when :name then name.to_s.singularize
|
||||||
|
else "#{name}_id"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def serializer_class(object, options = {})
|
||||||
|
(serializer_from_options unless object.nil?) || serializer_from_object(object, options) || default_serializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_serializer(object, options = {})
|
||||||
|
options[:_wrap_in_array] = embed_in_root?
|
||||||
|
super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
31
lib/active_model/serializer/config.rb
Normal file
31
lib/active_model/serializer/config.rb
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class Config
|
||||||
|
def initialize(data = {})
|
||||||
|
@data = data
|
||||||
|
end
|
||||||
|
|
||||||
|
def each(&block)
|
||||||
|
@data.each(&block)
|
||||||
|
end
|
||||||
|
|
||||||
|
def clear
|
||||||
|
@data.clear
|
||||||
|
end
|
||||||
|
|
||||||
|
def method_missing(name, *args)
|
||||||
|
name = name.to_s
|
||||||
|
return @data[name] if @data.include?(name)
|
||||||
|
match = name.match(/\A(.*?)([?=]?)\Z/)
|
||||||
|
case match[2]
|
||||||
|
when "="
|
||||||
|
@data[match[1]] = args.first
|
||||||
|
when "?"
|
||||||
|
!!@data[match[1]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
CONFIG = Config.new('embed' => :objects) # :nodoc:
|
||||||
|
end
|
||||||
|
end
|
||||||
13
lib/active_model/serializer/generators/resource_override.rb
Normal file
13
lib/active_model/serializer/generators/resource_override.rb
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
require 'rails/generators'
|
||||||
|
require 'rails/generators/rails/resource/resource_generator'
|
||||||
|
|
||||||
|
module Rails
|
||||||
|
module Generators
|
||||||
|
class ResourceGenerator
|
||||||
|
def add_serializer
|
||||||
|
invoke 'serializer'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
9
lib/active_model/serializer/generators/serializer/USAGE
Normal file
9
lib/active_model/serializer/generators/serializer/USAGE
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
Description:
|
||||||
|
Generates a serializer for the given resource with tests.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
`rails generate serializer Account name created_at`
|
||||||
|
|
||||||
|
For TestUnit it creates:
|
||||||
|
Serializer: app/serializers/account_serializer.rb
|
||||||
|
TestUnit: test/unit/account_serializer_test.rb
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
require 'rails/generators'
|
||||||
|
require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator'
|
||||||
|
|
||||||
|
module Rails
|
||||||
|
module Generators
|
||||||
|
class ScaffoldControllerGenerator
|
||||||
|
if Rails::VERSION::MAJOR >= 4
|
||||||
|
source_root File.expand_path('../templates', __FILE__)
|
||||||
|
|
||||||
|
hook_for :serializer, default: true, type: :boolean
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
module Rails
|
||||||
|
module Generators
|
||||||
|
class SerializerGenerator < NamedBase
|
||||||
|
source_root File.expand_path('../templates', __FILE__)
|
||||||
|
check_class_collision suffix: 'Serializer'
|
||||||
|
|
||||||
|
argument :attributes, type: :array, default: [], banner: 'field:type field:type'
|
||||||
|
|
||||||
|
class_option :parent, type: :string, desc: 'The parent class for the generated serializer'
|
||||||
|
|
||||||
|
def create_serializer_file
|
||||||
|
template 'serializer.rb', File.join('app/serializers', class_path, "#{file_name}_serializer.rb")
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def attributes_names
|
||||||
|
[:id] + attributes.select { |attr| !attr.reference? }.map { |a| a.name.to_sym }
|
||||||
|
end
|
||||||
|
|
||||||
|
def association_names
|
||||||
|
attributes.select { |attr| attr.reference? }.map { |a| a.name.to_sym }
|
||||||
|
end
|
||||||
|
|
||||||
|
def parent_class_name
|
||||||
|
if options[:parent]
|
||||||
|
options[:parent]
|
||||||
|
elsif (ns = Rails::Generators.namespace) && ns.const_defined?(:ApplicationSerializer) ||
|
||||||
|
(Object.const_get(:ApplicationSerializer) rescue nil)
|
||||||
|
'ApplicationSerializer'
|
||||||
|
else
|
||||||
|
'ActiveModel::Serializer'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,93 @@
|
|||||||
|
<% if namespaced? -%>
|
||||||
|
require_dependency "<%= namespaced_file_path %>/application_controller"
|
||||||
|
|
||||||
|
<% end -%>
|
||||||
|
<% module_namespacing do -%>
|
||||||
|
class <%= controller_class_name %>Controller < ApplicationController
|
||||||
|
before_action :set_<%= singular_table_name %>, only: [:show, :edit, :update, :destroy]
|
||||||
|
|
||||||
|
# GET <%= route_url %>
|
||||||
|
# GET <%= route_url %>.json
|
||||||
|
def index
|
||||||
|
@<%= plural_table_name %> = <%= orm_class.all(class_name) %>
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.html # index.html.erb
|
||||||
|
format.json { render json: <%= "@#{plural_table_name}" %> }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET <%= route_url %>/1
|
||||||
|
# GET <%= route_url %>/1.json
|
||||||
|
def show
|
||||||
|
respond_to do |format|
|
||||||
|
format.html # show.html.erb
|
||||||
|
format.json { render json: <%= "@#{singular_table_name}" %> }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET <%= route_url %>/new
|
||||||
|
def new
|
||||||
|
@<%= singular_table_name %> = <%= orm_class.build(class_name) %>
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET <%= route_url %>/1/edit
|
||||||
|
def edit
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST <%= route_url %>
|
||||||
|
# POST <%= route_url %>.json
|
||||||
|
def create
|
||||||
|
@<%= singular_table_name %> = <%= orm_class.build(class_name, "#{singular_table_name}_params") %>
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
if @<%= orm_instance.save %>
|
||||||
|
format.html { redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully created.'" %> }
|
||||||
|
format.json { render json: <%= "@#{singular_table_name}" %>, status: :created }
|
||||||
|
else
|
||||||
|
format.html { render action: 'new' }
|
||||||
|
format.json { render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# PATCH/PUT <%= route_url %>/1
|
||||||
|
# PATCH/PUT <%= route_url %>/1.json
|
||||||
|
def update
|
||||||
|
respond_to do |format|
|
||||||
|
if @<%= orm_instance.update("#{singular_table_name}_params") %>
|
||||||
|
format.html { redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully updated.'" %> }
|
||||||
|
format.json { head :no_content }
|
||||||
|
else
|
||||||
|
format.html { render action: 'edit' }
|
||||||
|
format.json { render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# DELETE <%= route_url %>/1
|
||||||
|
# DELETE <%= route_url %>/1.json
|
||||||
|
def destroy
|
||||||
|
@<%= orm_instance.destroy %>
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { redirect_to <%= index_helper %>_url }
|
||||||
|
format.json { head :no_content }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
# Use callbacks to share common setup or constraints between actions.
|
||||||
|
def set_<%= singular_table_name %>
|
||||||
|
@<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
|
||||||
|
end
|
||||||
|
|
||||||
|
# Never trust parameters from the scary internet, only allow the white list through.
|
||||||
|
def <%= "#{singular_table_name}_params" %>
|
||||||
|
<%- if attributes_names.empty? -%>
|
||||||
|
params[<%= ":#{singular_table_name}" %>]
|
||||||
|
<%- else -%>
|
||||||
|
params.require(<%= ":#{singular_table_name}" %>).permit(<%= attributes_names.map { |name| ":#{name}" }.join(', ') %>)
|
||||||
|
<%- end -%>
|
||||||
|
end
|
||||||
|
end
|
||||||
|
<% end -%>
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
<% module_namespacing do -%>
|
||||||
|
class <%= class_name %>Serializer < <%= parent_class_name %>
|
||||||
|
attributes <%= attributes_names.map(&:inspect).join(", ") %>
|
||||||
|
<% association_names.each do |attribute| -%>
|
||||||
|
has_one :<%= attribute %>
|
||||||
|
<% end -%>
|
||||||
|
end
|
||||||
|
<% end -%>
|
||||||
22
lib/active_model/serializer/railtie.rb
Normal file
22
lib/active_model/serializer/railtie.rb
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
module ActiveModel
|
||||||
|
class Railtie < Rails::Railtie
|
||||||
|
initializer 'generators' do |app|
|
||||||
|
app.load_generators
|
||||||
|
require 'active_model/serializer/generators/serializer/serializer_generator'
|
||||||
|
require 'active_model/serializer/generators/serializer/scaffold_controller_generator'
|
||||||
|
require 'active_model/serializer/generators/resource_override'
|
||||||
|
end
|
||||||
|
|
||||||
|
initializer 'include_routes.active_model_serializer' do |app|
|
||||||
|
ActiveSupport.on_load(:active_model_serializers) do
|
||||||
|
include app.routes.url_helpers
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
config.to_prepare do
|
||||||
|
ActiveModel::Serializer.serializers_cache.clear
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ActiveSupport.run_load_hooks(:active_model_serializers, ActiveModel::Serializer)
|
||||||
5
lib/active_model/serializer/version.rb
Normal file
5
lib/active_model/serializer/version.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
VERSION = '0.9.7'
|
||||||
|
end
|
||||||
|
end
|
||||||
5
lib/active_model/serializer_support.rb
Normal file
5
lib/active_model/serializer_support.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module ActiveModel
|
||||||
|
module SerializerSupport
|
||||||
|
alias read_attribute_for_serialization send
|
||||||
|
end
|
||||||
|
end
|
||||||
20
lib/active_model_serializers.rb
Normal file
20
lib/active_model_serializers.rb
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
require 'active_model'
|
||||||
|
require 'active_model/serializer'
|
||||||
|
require 'active_model/serializer_support'
|
||||||
|
require 'active_model/serializer/version'
|
||||||
|
require 'active_model/serializer/railtie' if defined?(Rails)
|
||||||
|
|
||||||
|
begin
|
||||||
|
require 'action_controller'
|
||||||
|
require 'action_controller/serialization'
|
||||||
|
require 'action_controller/serialization_test_case'
|
||||||
|
|
||||||
|
ActiveSupport.on_load(:action_controller) do
|
||||||
|
if ::ActionController::Serialization.enabled
|
||||||
|
ActionController::Base.send(:include, ::ActionController::Serialization)
|
||||||
|
ActionController::TestCase.send(:include, ::ActionController::SerializationAssertions)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rescue LoadError
|
||||||
|
# rails not installed, continuing
|
||||||
|
end
|
||||||
60
test/benchmark/app.rb
Normal file
60
test/benchmark/app.rb
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# https://github.com/rails-api/active_model_serializers/pull/872
|
||||||
|
# approx ref 792fb8a9053f8db3c562dae4f40907a582dd1720 to test against
|
||||||
|
require 'bundler/setup'
|
||||||
|
|
||||||
|
require 'rails'
|
||||||
|
require 'active_model'
|
||||||
|
require 'active_support'
|
||||||
|
require 'active_support/json'
|
||||||
|
require 'action_controller'
|
||||||
|
require 'action_controller/test_case'
|
||||||
|
require 'action_controller/railtie'
|
||||||
|
abort "Rails application already defined: #{Rails.application.class}" if Rails.application
|
||||||
|
|
||||||
|
class NullLogger < Logger
|
||||||
|
def initialize(*_args)
|
||||||
|
end
|
||||||
|
|
||||||
|
def add(*_args, &_block)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
class BenchmarkLogger < ActiveSupport::Logger
|
||||||
|
def initialize
|
||||||
|
@file = StringIO.new
|
||||||
|
super(@file)
|
||||||
|
end
|
||||||
|
|
||||||
|
def messages
|
||||||
|
@file.rewind
|
||||||
|
@file.read
|
||||||
|
end
|
||||||
|
end
|
||||||
|
# ref: https://gist.github.com/bf4/8744473
|
||||||
|
class BenchmarkApp < Rails::Application
|
||||||
|
# Set up production configuration
|
||||||
|
config.eager_load = true
|
||||||
|
config.cache_classes = true
|
||||||
|
# CONFIG: CACHE_ON={on,off}
|
||||||
|
config.action_controller.perform_caching = ENV['CACHE_ON'] != 'off'
|
||||||
|
config.action_controller.cache_store = ActiveSupport::Cache.lookup_store(:memory_store)
|
||||||
|
|
||||||
|
config.active_support.test_order = :random
|
||||||
|
config.secret_token = 'S' * 30
|
||||||
|
config.secret_key_base = 'abc123'
|
||||||
|
config.consider_all_requests_local = false
|
||||||
|
|
||||||
|
# otherwise deadlock occurred
|
||||||
|
config.middleware.delete 'Rack::Lock'
|
||||||
|
|
||||||
|
# to disable log files
|
||||||
|
config.logger = NullLogger.new
|
||||||
|
config.active_support.deprecation = :log
|
||||||
|
config.log_level = :info
|
||||||
|
end
|
||||||
|
|
||||||
|
require 'active_model_serializers'
|
||||||
|
|
||||||
|
# Initialize app before any serializers are defined, for running across revisions.
|
||||||
|
# ref: https://github.com/rails-api/active_model_serializers/pull/1478
|
||||||
|
Rails.application.initialize!
|
||||||
|
|
||||||
67
test/benchmark/benchmarking_support.rb
Normal file
67
test/benchmark/benchmarking_support.rb
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
require 'benchmark/ips'
|
||||||
|
require 'json'
|
||||||
|
|
||||||
|
# Add benchmarking runner from ruby-bench-suite
|
||||||
|
# https://github.com/ruby-bench/ruby-bench-suite/blob/master/rails/benchmarks/support/benchmark_rails.rb
|
||||||
|
module Benchmark
|
||||||
|
module ActiveModelSerializers
|
||||||
|
module TestMethods
|
||||||
|
def request(method, path)
|
||||||
|
response = Rack::MockRequest.new(BenchmarkApp).send(method, path)
|
||||||
|
if response.status.in?([404, 500])
|
||||||
|
fail "omg, #{method}, #{path}, '#{response.status}', '#{response.body}'"
|
||||||
|
end
|
||||||
|
response
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# extend Benchmark with an `ams` method
|
||||||
|
def ams(label = nil, time:, disable_gc: true, warmup: 3, &block)
|
||||||
|
fail ArgumentError.new, 'block should be passed' unless block_given?
|
||||||
|
|
||||||
|
if disable_gc
|
||||||
|
GC.disable
|
||||||
|
else
|
||||||
|
GC.enable
|
||||||
|
end
|
||||||
|
|
||||||
|
report = Benchmark.ips(time, warmup, true) do |x|
|
||||||
|
x.report(label) { yield }
|
||||||
|
end
|
||||||
|
|
||||||
|
entry = report.entries.first
|
||||||
|
|
||||||
|
output = {
|
||||||
|
label: label,
|
||||||
|
version: ::ActiveModel::Serializer::VERSION.to_s,
|
||||||
|
rails_version: ::Rails.version.to_s,
|
||||||
|
iterations_per_second: entry.ips,
|
||||||
|
iterations_per_second_standard_deviation: entry.error_percentage,
|
||||||
|
total_allocated_objects_per_iteration: count_total_allocated_objects(&block)
|
||||||
|
}.to_json
|
||||||
|
|
||||||
|
puts output
|
||||||
|
output
|
||||||
|
end
|
||||||
|
|
||||||
|
def count_total_allocated_objects
|
||||||
|
if block_given?
|
||||||
|
key =
|
||||||
|
if RUBY_VERSION < '2.2'
|
||||||
|
:total_allocated_object
|
||||||
|
else
|
||||||
|
:total_allocated_objects
|
||||||
|
end
|
||||||
|
|
||||||
|
before = GC.stat[key]
|
||||||
|
yield
|
||||||
|
after = GC.stat[key]
|
||||||
|
after - before
|
||||||
|
else
|
||||||
|
-1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
extend Benchmark::ActiveModelSerializers
|
||||||
|
end
|
||||||
41
test/benchmark/bm_active_record.rb
Normal file
41
test/benchmark/bm_active_record.rb
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
require_relative './benchmarking_support'
|
||||||
|
require_relative './app'
|
||||||
|
require_relative './setup'
|
||||||
|
|
||||||
|
time = 10
|
||||||
|
disable_gc = true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
authors_query = Author.preload(:posts).preload(:profile)
|
||||||
|
author = authors_query.first
|
||||||
|
authors = authors_query.to_a
|
||||||
|
|
||||||
|
|
||||||
|
Benchmark.ams('Single: DefaultSerializer', time: time, disable_gc: disable_gc) do
|
||||||
|
ActiveModel::DefaultSerializer.new(author).to_json
|
||||||
|
end
|
||||||
|
|
||||||
|
Benchmark.ams('ArraySerializer', time: time, disable_gc: disable_gc) do
|
||||||
|
ActiveModel::ArraySerializer.new(authors).to_json
|
||||||
|
end
|
||||||
|
|
||||||
|
Benchmark.ams('ArraySerializer: each_serializer: DefaultSerializer', time: time, disable_gc: disable_gc) do
|
||||||
|
ActiveModel::ArraySerializer.new(authors, each_serializer:ActiveModel::DefaultSerializer).to_json
|
||||||
|
end
|
||||||
|
|
||||||
|
Benchmark.ams('FlatAuthorSerializer', time: time, disable_gc: disable_gc) do
|
||||||
|
FlatAuthorSerializer.new(author).to_json
|
||||||
|
end
|
||||||
|
|
||||||
|
Benchmark.ams('ArraySerializer: each_serializer: FlatAuthorSerializer', time: time, disable_gc: disable_gc) do
|
||||||
|
ActiveModel::ArraySerializer.new(authors, each_serializer: FlatAuthorSerializer).to_json
|
||||||
|
end
|
||||||
|
|
||||||
|
Benchmark.ams('AuthorWithDefaultRelationshipsSerializer', time: time, disable_gc: disable_gc) do
|
||||||
|
AuthorWithDefaultRelationshipsSerializer.new(author).to_json
|
||||||
|
end
|
||||||
|
|
||||||
|
Benchmark.ams('ArraySerializer: each_serializer: AuthorWithDefaultRelationshipsSerializer', time: time, disable_gc: disable_gc) do
|
||||||
|
ActiveModel::ArraySerializer.new(authors, each_serializer: AuthorWithDefaultRelationshipsSerializer).to_json
|
||||||
|
end
|
||||||
75
test/benchmark/setup.rb
Normal file
75
test/benchmark/setup.rb
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
###########################################
|
||||||
|
# Setup active record models
|
||||||
|
##########################################
|
||||||
|
require 'active_record'
|
||||||
|
require 'sqlite3'
|
||||||
|
|
||||||
|
|
||||||
|
# Change the following to reflect your database settings
|
||||||
|
ActiveRecord::Base.establish_connection(
|
||||||
|
adapter: 'sqlite3',
|
||||||
|
database: ':memory:'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Don't show migration output when constructing fake db
|
||||||
|
ActiveRecord::Migration.verbose = false
|
||||||
|
|
||||||
|
ActiveRecord::Schema.define do
|
||||||
|
create_table :authors, force: true do |t|
|
||||||
|
t.string :name
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table :posts, force: true do |t|
|
||||||
|
t.text :body
|
||||||
|
t.string :title
|
||||||
|
t.references :author
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table :profiles, force: true do |t|
|
||||||
|
t.text :project_url
|
||||||
|
t.text :bio
|
||||||
|
t.date :birthday
|
||||||
|
t.references :author
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Author < ActiveRecord::Base
|
||||||
|
has_one :profile
|
||||||
|
has_many :posts
|
||||||
|
end
|
||||||
|
|
||||||
|
class Post < ActiveRecord::Base
|
||||||
|
belongs_to :author
|
||||||
|
end
|
||||||
|
|
||||||
|
class Profile < ActiveRecord::Base
|
||||||
|
belongs_to :author
|
||||||
|
end
|
||||||
|
|
||||||
|
# Build out the data to serialize
|
||||||
|
author = Author.create(name: 'Preston Sego')
|
||||||
|
Profile.create(project_url: 'https://github.com/NullVoxPopuli', author: author)
|
||||||
|
50.times do
|
||||||
|
Post.create(
|
||||||
|
body: 'something about how password restrictions are evil, and less secure, and with the math to prove it.',
|
||||||
|
title: 'Your bank is does not know how to do security',
|
||||||
|
author: author
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
ActiveModel::Serializer.root = false
|
||||||
|
ActiveModel::ArraySerializer.root = false
|
||||||
|
|
||||||
|
class FlatAuthorSerializer < ActiveModel::Serializer
|
||||||
|
attributes :id, :name
|
||||||
|
end
|
||||||
|
|
||||||
|
class AuthorWithDefaultRelationshipsSerializer < ActiveModel::Serializer
|
||||||
|
attributes :id, :name
|
||||||
|
|
||||||
|
has_one :profile
|
||||||
|
has_many :posts
|
||||||
|
end
|
||||||
|
|
||||||
|
# For debugging SQL output
|
||||||
|
#ActiveRecord::Base.logger = Logger.new(STDERR)
|
||||||
96
test/fixtures/active_record.rb
vendored
Normal file
96
test/fixtures/active_record.rb
vendored
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
require 'active_record'
|
||||||
|
|
||||||
|
ActiveRecord::Base.establish_connection(
|
||||||
|
:adapter => 'sqlite3',
|
||||||
|
:database => ':memory:'
|
||||||
|
)
|
||||||
|
|
||||||
|
ActiveRecord::Schema.define do
|
||||||
|
create_table :ar_posts, force: true do |t|
|
||||||
|
t.string :title
|
||||||
|
t.text :body
|
||||||
|
t.belongs_to :ar_section, index: true
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table :ar_comments, force: true do |t|
|
||||||
|
t.text :body
|
||||||
|
t.belongs_to :ar_post, index: true
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table :ar_tags, force: true do |t|
|
||||||
|
t.string :name
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table :ar_sections, force: true do |t|
|
||||||
|
t.string :name
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table :ar_posts_tags, force: true do |t|
|
||||||
|
t.references :ar_post, :ar_tag, index: true
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table :ar_comments_tags, force: true do |t|
|
||||||
|
t.references :ar_comment, :ar_tag, index: true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ARPost < ActiveRecord::Base
|
||||||
|
has_many :ar_comments, class_name: 'ARComment'
|
||||||
|
has_and_belongs_to_many :ar_tags, class_name: 'ARTag', join_table: :ar_posts_tags
|
||||||
|
belongs_to :ar_section, class_name: 'ARSection'
|
||||||
|
end
|
||||||
|
|
||||||
|
class ARComment < ActiveRecord::Base
|
||||||
|
belongs_to :ar_post, class_name: 'ARPost'
|
||||||
|
has_and_belongs_to_many :ar_tags, class_name: 'ARTag', join_table: :ar_comments_tags
|
||||||
|
end
|
||||||
|
|
||||||
|
class ARTag < ActiveRecord::Base
|
||||||
|
end
|
||||||
|
|
||||||
|
class ARSection < ActiveRecord::Base
|
||||||
|
end
|
||||||
|
|
||||||
|
class ARPostSerializer < ActiveModel::Serializer
|
||||||
|
attributes :title, :body
|
||||||
|
|
||||||
|
has_many :ar_comments, :ar_tags
|
||||||
|
has_one :ar_section
|
||||||
|
end
|
||||||
|
|
||||||
|
class ARCommentSerializer < ActiveModel::Serializer
|
||||||
|
attributes :body
|
||||||
|
|
||||||
|
has_many :ar_tags
|
||||||
|
end
|
||||||
|
|
||||||
|
class ARTagSerializer < ActiveModel::Serializer
|
||||||
|
attributes :name
|
||||||
|
end
|
||||||
|
|
||||||
|
class ARSectionSerializer < ActiveModel::Serializer
|
||||||
|
attributes 'name'
|
||||||
|
end
|
||||||
|
|
||||||
|
class AREmbeddedSerializer < ActiveModel::Serializer
|
||||||
|
has_many :ar_tags, :ar_comments
|
||||||
|
end
|
||||||
|
|
||||||
|
ARPost.create(title: 'New post',
|
||||||
|
body: 'A body!!!',
|
||||||
|
ar_section: ARSection.create(name: 'ruby')).tap do |post|
|
||||||
|
|
||||||
|
short_tag = post.ar_tags.create(name: 'short')
|
||||||
|
whiny_tag = post.ar_tags.create(name: 'whiny')
|
||||||
|
happy_tag = ARTag.create(name: 'happy')
|
||||||
|
|
||||||
|
post.ar_comments.create(body: 'what a dumb post').tap do |comment|
|
||||||
|
comment.ar_tags.concat happy_tag, whiny_tag
|
||||||
|
end
|
||||||
|
|
||||||
|
post.ar_comments.create(body: 'i liked it').tap do |comment|
|
||||||
|
comment.ar_tags.concat happy_tag, short_tag
|
||||||
|
end
|
||||||
|
end
|
||||||
223
test/fixtures/poro.rb
vendored
Normal file
223
test/fixtures/poro.rb
vendored
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
class Model
|
||||||
|
def initialize(hash = {})
|
||||||
|
@attributes = hash
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_attribute_for_serialization(name)
|
||||||
|
if name == :id || name == 'id'
|
||||||
|
object_id
|
||||||
|
elsif respond_to?(name)
|
||||||
|
send name
|
||||||
|
else
|
||||||
|
@attributes[name]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
## Models
|
||||||
|
###
|
||||||
|
class User < Model
|
||||||
|
def profile
|
||||||
|
@profile ||= Profile.new(name: 'N1', description: 'D1')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class UserInfo < Model
|
||||||
|
def user
|
||||||
|
@user ||= User.new(name: 'N1', email: 'E1')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Profile < Model
|
||||||
|
end
|
||||||
|
|
||||||
|
class Category < Model
|
||||||
|
def posts
|
||||||
|
@posts ||= [Post.new(title: 'T1', body: 'B1'),
|
||||||
|
Post.new(title: 'T2', body: 'B2')]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Post < Model
|
||||||
|
def comments
|
||||||
|
@comments ||= [Comment.new(content: 'C1'),
|
||||||
|
Comment.new(content: 'C2')]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class SpecialPost < Post
|
||||||
|
def special_comment
|
||||||
|
@special_comment ||= Comment.new(content: 'special')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Type < Model
|
||||||
|
end
|
||||||
|
|
||||||
|
class SelfReferencingUser < Model
|
||||||
|
def type
|
||||||
|
@type ||= Type.new(name: 'N1')
|
||||||
|
end
|
||||||
|
def parent
|
||||||
|
@parent ||= SelfReferencingUserParent.new(name: 'N1')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class SelfReferencingUserParent < Model
|
||||||
|
def type
|
||||||
|
@type ||= Type.new(name: 'N2')
|
||||||
|
end
|
||||||
|
def parent
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Comment < Model
|
||||||
|
end
|
||||||
|
|
||||||
|
class WebLog < Model
|
||||||
|
end
|
||||||
|
|
||||||
|
class Interview < Model
|
||||||
|
def attachment
|
||||||
|
@attachment ||= Image.new(url: 'U1')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Mail < Model
|
||||||
|
def attachments
|
||||||
|
@attachments ||= [Image.new(url: 'U1'),
|
||||||
|
Video.new(html: 'H1')]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Image < Model
|
||||||
|
end
|
||||||
|
|
||||||
|
class Video < Model
|
||||||
|
end
|
||||||
|
|
||||||
|
###
|
||||||
|
## Serializers
|
||||||
|
###
|
||||||
|
class UserSerializer < ActiveModel::Serializer
|
||||||
|
attributes :name, :email
|
||||||
|
|
||||||
|
has_one :profile
|
||||||
|
end
|
||||||
|
|
||||||
|
class TypeSerializer < ActiveModel::Serializer
|
||||||
|
attributes :name
|
||||||
|
end
|
||||||
|
|
||||||
|
class SelfReferencingUserParentSerializer < ActiveModel::Serializer
|
||||||
|
attributes :name
|
||||||
|
has_one :type, serializer: TypeSerializer, embed: :ids, include: true
|
||||||
|
end
|
||||||
|
|
||||||
|
class SelfReferencingUserSerializer < ActiveModel::Serializer
|
||||||
|
attributes :name
|
||||||
|
|
||||||
|
has_one :type, serializer: TypeSerializer, embed: :ids, include: true
|
||||||
|
has_one :parent, serializer: SelfReferencingUserSerializer, embed: :ids, include: true
|
||||||
|
end
|
||||||
|
|
||||||
|
class UserInfoSerializer < ActiveModel::Serializer
|
||||||
|
has_one :user, serializer: UserSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
class ProfileSerializer < ActiveModel::Serializer
|
||||||
|
def description
|
||||||
|
description = object.read_attribute_for_serialization(:description)
|
||||||
|
scope ? "#{description} - #{scope}" : description
|
||||||
|
end
|
||||||
|
|
||||||
|
attributes :name, :description
|
||||||
|
end
|
||||||
|
|
||||||
|
class CategorySerializer < ActiveModel::Serializer
|
||||||
|
attributes :name
|
||||||
|
|
||||||
|
has_many :posts
|
||||||
|
end
|
||||||
|
|
||||||
|
class PostSerializer < ActiveModel::Serializer
|
||||||
|
attributes :title, :body
|
||||||
|
|
||||||
|
def title
|
||||||
|
keyword = serialization_options[:highlight_keyword]
|
||||||
|
title = object.read_attribute_for_serialization(:title)
|
||||||
|
title = title.gsub(keyword,"'#{keyword}'") if keyword
|
||||||
|
title
|
||||||
|
end
|
||||||
|
|
||||||
|
has_many :comments
|
||||||
|
end
|
||||||
|
|
||||||
|
class SpecialPostSerializer < ActiveModel::Serializer
|
||||||
|
attributes :title, :body
|
||||||
|
has_many :comments, root: :comments, embed_in_root: true, embed: :ids
|
||||||
|
has_one :special_comment, root: :comments, embed_in_root: true, embed: :ids
|
||||||
|
end
|
||||||
|
|
||||||
|
class CommentSerializer < ActiveModel::Serializer
|
||||||
|
attributes :content
|
||||||
|
end
|
||||||
|
|
||||||
|
class WebLogSerializer < ActiveModel::Serializer
|
||||||
|
attributes :name, :display_name
|
||||||
|
end
|
||||||
|
|
||||||
|
class WebLogLowerCamelSerializer < WebLogSerializer
|
||||||
|
format_keys :lower_camel
|
||||||
|
end
|
||||||
|
|
||||||
|
class InterviewSerializer < ActiveModel::Serializer
|
||||||
|
attributes :text
|
||||||
|
|
||||||
|
has_one :attachment, polymorphic: true
|
||||||
|
end
|
||||||
|
|
||||||
|
class MailSerializer < ActiveModel::Serializer
|
||||||
|
attributes :body
|
||||||
|
|
||||||
|
has_many :attachments, polymorphic: true
|
||||||
|
end
|
||||||
|
|
||||||
|
class ImageSerializer < ActiveModel::Serializer
|
||||||
|
attributes :url
|
||||||
|
end
|
||||||
|
|
||||||
|
class VideoSerializer < ActiveModel::Serializer
|
||||||
|
attributes :html
|
||||||
|
end
|
||||||
|
|
||||||
|
class ShortProfileSerializer < ::ProfileSerializer; end
|
||||||
|
|
||||||
|
module TestNamespace
|
||||||
|
class ProfileSerializer < ::ProfileSerializer; end
|
||||||
|
class UserSerializer < ::UserSerializer; end
|
||||||
|
end
|
||||||
|
|
||||||
|
ActiveModel::Serializer.setup do |config|
|
||||||
|
config.default_key_type = :name
|
||||||
|
end
|
||||||
|
|
||||||
|
class NameKeyUserSerializer < ActiveModel::Serializer
|
||||||
|
attributes :name, :email
|
||||||
|
|
||||||
|
has_one :profile
|
||||||
|
end
|
||||||
|
|
||||||
|
class NameKeyPostSerializer < ActiveModel::Serializer
|
||||||
|
attributes :title, :body
|
||||||
|
|
||||||
|
has_many :comments
|
||||||
|
end
|
||||||
|
|
||||||
|
ActiveModel::Serializer.setup do |config|
|
||||||
|
config.default_key_type = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
1
test/fixtures/template.html.erb
vendored
Normal file
1
test/fixtures/template.html.erb
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
<p>Hello.</p>
|
||||||
@ -0,0 +1,105 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActionController
|
||||||
|
module Serialization
|
||||||
|
class NamespacedSerializationTest < ActionController::TestCase
|
||||||
|
class TestNamespace::MyController < ActionController::Base
|
||||||
|
def render_profile_with_namespace
|
||||||
|
render json: Profile.new({ name: 'Name 1', description: 'Description 1'})
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_profiles_with_namespace
|
||||||
|
render json: [Profile.new({ name: 'Name 1', description: 'Description 1'})]
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_comment
|
||||||
|
render json: Comment.new(content: 'Comment 1')
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_comments
|
||||||
|
render json: [Comment.new(content: 'Comment 1')]
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_hash
|
||||||
|
render json: {message: 'not found'}, status: 404
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tests TestNamespace::MyController
|
||||||
|
|
||||||
|
def test_render_profile_with_namespace
|
||||||
|
get :render_profile_with_namespace
|
||||||
|
assert_serializer TestNamespace::ProfileSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_render_profiles_with_namespace
|
||||||
|
get :render_profiles_with_namespace
|
||||||
|
assert_serializer TestNamespace::ProfileSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_fallback_to_a_version_without_namespace
|
||||||
|
get :render_comment
|
||||||
|
assert_serializer CommentSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_array_fallback_to_a_version_without_namespace
|
||||||
|
get :render_comments
|
||||||
|
assert_serializer CommentSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_render_hash_regression
|
||||||
|
get :render_hash
|
||||||
|
assert_equal JSON.parse(response.body), {'message' => 'not found'}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class OptionNamespacedSerializationTest < ActionController::TestCase
|
||||||
|
class MyController < ActionController::Base
|
||||||
|
def default_serializer_options
|
||||||
|
{
|
||||||
|
namespace: TestNamespace
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_profile_with_namespace_option
|
||||||
|
render json: Profile.new({ name: 'Name 1', description: 'Description 1'})
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_profiles_with_namespace_option
|
||||||
|
render json: [Profile.new({ name: 'Name 1', description: 'Description 1'})]
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_comment
|
||||||
|
render json: Comment.new(content: 'Comment 1')
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_comments
|
||||||
|
render json: [Comment.new(content: 'Comment 1')]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tests MyController
|
||||||
|
|
||||||
|
def test_render_profile_with_namespace_option
|
||||||
|
get :render_profile_with_namespace_option
|
||||||
|
assert_serializer TestNamespace::ProfileSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_render_profiles_with_namespace_option
|
||||||
|
get :render_profiles_with_namespace_option
|
||||||
|
assert_serializer TestNamespace::ProfileSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_fallback_to_a_version_without_namespace
|
||||||
|
get :render_comment
|
||||||
|
assert_serializer CommentSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_array_fallback_to_a_version_without_namespace
|
||||||
|
get :render_comments
|
||||||
|
assert_serializer CommentSerializer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
287
test/integration/action_controller/serialization_test.rb
Normal file
287
test/integration/action_controller/serialization_test.rb
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActionController
|
||||||
|
module Serialization
|
||||||
|
class ImplicitSerializerTest < ActionController::TestCase
|
||||||
|
class MyController < ActionController::Base
|
||||||
|
def render_using_implicit_serializer
|
||||||
|
render json: Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tests MyController
|
||||||
|
|
||||||
|
def test_render_using_implicit_serializer
|
||||||
|
get :render_using_implicit_serializer
|
||||||
|
assert_equal 'application/json', @response.content_type
|
||||||
|
assert_equal '{"profile":{"name":"Name 1","description":"Description 1"}}', @response.body
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ImplicitSerializerScopeTest < ActionController::TestCase
|
||||||
|
class MyController < ActionController::Base
|
||||||
|
def render_using_implicit_serializer_and_scope
|
||||||
|
render json: Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def current_user
|
||||||
|
'current_user'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tests MyController
|
||||||
|
|
||||||
|
def test_render_using_implicit_serializer_and_scope
|
||||||
|
get :render_using_implicit_serializer_and_scope
|
||||||
|
assert_equal 'application/json', @response.content_type
|
||||||
|
assert_equal '{"profile":{"name":"Name 1","description":"Description 1 - current_user"}}', @response.body
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class DefaultOptionsForSerializerScopeTest < ActionController::TestCase
|
||||||
|
class MyController < ActionController::Base
|
||||||
|
def default_serializer_options
|
||||||
|
{ scope: current_admin }
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_using_scope_set_in_default_serializer_options
|
||||||
|
render json: Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def current_user
|
||||||
|
'current_user'
|
||||||
|
end
|
||||||
|
|
||||||
|
def current_admin
|
||||||
|
'current_admin'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tests MyController
|
||||||
|
|
||||||
|
def test_render_using_scope_set_in_default_serializer_options
|
||||||
|
get :render_using_scope_set_in_default_serializer_options
|
||||||
|
assert_equal 'application/json', @response.content_type
|
||||||
|
assert_equal '{"profile":{"name":"Name 1","description":"Description 1 - current_admin"}}', @response.body
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ExplicitSerializerScopeTest < ActionController::TestCase
|
||||||
|
class MyController < ActionController::Base
|
||||||
|
def render_using_implicit_serializer_and_explicit_scope
|
||||||
|
render json: Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' }), scope: current_admin
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def current_user
|
||||||
|
'current_user'
|
||||||
|
end
|
||||||
|
|
||||||
|
def current_admin
|
||||||
|
'current_admin'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tests MyController
|
||||||
|
|
||||||
|
def test_render_using_implicit_serializer_and_explicit_scope
|
||||||
|
get :render_using_implicit_serializer_and_explicit_scope
|
||||||
|
assert_equal 'application/json', @response.content_type
|
||||||
|
assert_equal '{"profile":{"name":"Name 1","description":"Description 1 - current_admin"}}', @response.body
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class OverridingSerializationScopeTest < ActionController::TestCase
|
||||||
|
class MyController < ActionController::Base
|
||||||
|
def render_overriding_serialization_scope
|
||||||
|
render json: Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def current_user
|
||||||
|
'current_user'
|
||||||
|
end
|
||||||
|
|
||||||
|
def serialization_scope
|
||||||
|
'current_admin'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tests MyController
|
||||||
|
|
||||||
|
def test_render_overriding_serialization_scope
|
||||||
|
get :render_overriding_serialization_scope
|
||||||
|
assert_equal 'application/json', @response.content_type
|
||||||
|
assert_equal '{"profile":{"name":"Name 1","description":"Description 1 - current_admin"}}', @response.body
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class CallingSerializationScopeTest < ActionController::TestCase
|
||||||
|
class MyController < ActionController::Base
|
||||||
|
def render_calling_serialization_scope
|
||||||
|
render json: Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def current_user
|
||||||
|
'current_user'
|
||||||
|
end
|
||||||
|
|
||||||
|
serialization_scope :current_user
|
||||||
|
end
|
||||||
|
|
||||||
|
tests MyController
|
||||||
|
|
||||||
|
def test_render_calling_serialization_scope
|
||||||
|
get :render_calling_serialization_scope
|
||||||
|
assert_equal 'application/json', @response.content_type
|
||||||
|
assert_equal '{"profile":{"name":"Name 1","description":"Description 1 - current_user"}}', @response.body
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class JSONDumpSerializerTest < ActionController::TestCase
|
||||||
|
class MyController < ActionController::Base
|
||||||
|
def render_using_json_dump
|
||||||
|
render json: JSON.dump(hello: 'world')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tests MyController
|
||||||
|
|
||||||
|
def test_render_using_json_dump
|
||||||
|
get :render_using_json_dump
|
||||||
|
assert_equal 'application/json', @response.content_type
|
||||||
|
assert_equal '{"hello":"world"}', @response.body
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class RailsSerializerTest < ActionController::TestCase
|
||||||
|
class MyController < ActionController::Base
|
||||||
|
def render_using_rails_behavior
|
||||||
|
render json: [Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })], serializer: false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tests MyController
|
||||||
|
|
||||||
|
def test_render_using_rails_behavior
|
||||||
|
get :render_using_rails_behavior
|
||||||
|
assert_equal 'application/json', @response.content_type
|
||||||
|
assert_equal '[{"attributes":{"name":"Name 1","description":"Description 1","comments":"Comments 1"}}]', @response.body
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ArraySerializerTest < ActionController::TestCase
|
||||||
|
class MyController < ActionController::Base
|
||||||
|
def render_array
|
||||||
|
render json: [Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tests MyController
|
||||||
|
|
||||||
|
def test_render_array
|
||||||
|
get :render_array
|
||||||
|
assert_equal 'application/json', @response.content_type
|
||||||
|
assert_equal '{"my":[{"name":"Name 1","description":"Description 1"}]}', @response.body
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class LowerCamelArraySerializerTest < ActionController::TestCase
|
||||||
|
class WebLogController < ActionController::Base
|
||||||
|
def render_array
|
||||||
|
render json: [WebLog.new({name: 'Name 1', display_name: 'Display Name 1'}), WebLog.new({name: 'Name 2', display_name: 'Display Name 2'})], each_serializer: WebLogLowerCamelSerializer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tests WebLogController
|
||||||
|
|
||||||
|
def test_render_array
|
||||||
|
get :render_array
|
||||||
|
assert_equal 'application/json', @response.content_type
|
||||||
|
assert_equal '{"webLog":[{"name":"Name 1","displayName":"Display Name 1"},{"name":"Name 2","displayName":"Display Name 2"}]}', @response.body
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class LowerCamelWoRootSerializerTest < ActionController::TestCase
|
||||||
|
class WebLogController < ActionController::Base
|
||||||
|
def render_without_root
|
||||||
|
render json: WebLog.new({name: 'Name 1', display_name: 'Display Name 1'}),
|
||||||
|
root: false,
|
||||||
|
serializer: WebLogLowerCamelSerializer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tests WebLogController
|
||||||
|
|
||||||
|
def test_render_without_root
|
||||||
|
get :render_without_root
|
||||||
|
assert_equal 'application/json', @response.content_type
|
||||||
|
assert_equal '{"name":"Name 1","displayName":"Display Name 1"}', @response.body
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class LowerCamelArrayWoRootSerializerTest < ActionController::TestCase
|
||||||
|
class WebLogController < ActionController::Base
|
||||||
|
def render_array_without_root
|
||||||
|
render json: [WebLog.new({name: 'Name 1', display_name: 'Display Name 1'}),
|
||||||
|
WebLog.new({name: 'Name 2', display_name: 'Display Name 2'})],
|
||||||
|
root: false,
|
||||||
|
each_serializer: WebLogLowerCamelSerializer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tests WebLogController
|
||||||
|
|
||||||
|
def test_render_array_without_root
|
||||||
|
get :render_array_without_root
|
||||||
|
assert_equal 'application/json', @response.content_type
|
||||||
|
assert_equal '[{"name":"Name 1","displayName":"Display Name 1"},{"name":"Name 2","displayName":"Display Name 2"}]', @response.body
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ArrayEmbedingSerializerTest < ActionController::TestCase
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
@association = UserSerializer._associations[:profile]
|
||||||
|
@old_association = @association.dup
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
super
|
||||||
|
UserSerializer._associations[:profile] = @old_association
|
||||||
|
end
|
||||||
|
|
||||||
|
class MyController < ActionController::Base
|
||||||
|
def initialize(*)
|
||||||
|
super
|
||||||
|
@user = User.new({ name: 'Name 1', email: 'mail@server.com', gender: 'M' })
|
||||||
|
end
|
||||||
|
attr_reader :user
|
||||||
|
|
||||||
|
def render_array_embeding_in_root
|
||||||
|
render json: [@user]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tests MyController
|
||||||
|
|
||||||
|
def test_render_array_embeding_in_root
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
|
||||||
|
get :render_array_embeding_in_root
|
||||||
|
assert_equal 'application/json', @response.content_type
|
||||||
|
|
||||||
|
assert_equal("{\"my\":[{\"name\":\"Name 1\",\"email\":\"mail@server.com\",\"profile_id\":#{@controller.user.profile.object_id}}],\"profiles\":[{\"name\":\"N1\",\"description\":\"D1\"}]}", @response.body)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActionController
|
||||||
|
module SerializationsAssertions
|
||||||
|
class RenderSerializerTest < ActionController::TestCase
|
||||||
|
class MyController < ActionController::Base
|
||||||
|
def render_using_serializer
|
||||||
|
render json: Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_text
|
||||||
|
render text: 'ok'
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_template
|
||||||
|
prepend_view_path "./test/fixtures"
|
||||||
|
render template: "template"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tests MyController
|
||||||
|
|
||||||
|
def test_supports_specifying_serializers_with_a_serializer_class
|
||||||
|
get :render_using_serializer
|
||||||
|
assert_serializer ProfileSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_supports_specifying_serializers_with_a_regexp
|
||||||
|
get :render_using_serializer
|
||||||
|
assert_serializer %r{\AProfile.+\Z}
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_supports_specifying_serializers_with_a_string
|
||||||
|
get :render_using_serializer
|
||||||
|
assert_serializer 'ProfileSerializer'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_supports_specifying_serializers_with_a_symbol
|
||||||
|
get :render_using_serializer
|
||||||
|
assert_serializer :profile_serializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_supports_specifying_serializers_with_a_nil
|
||||||
|
get :render_text
|
||||||
|
assert_serializer nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_raises_descriptive_error_message_when_serializer_was_not_rendered
|
||||||
|
get :render_using_serializer
|
||||||
|
e = assert_raise ActiveSupport::TestCase::Assertion do
|
||||||
|
assert_serializer 'PostSerializer'
|
||||||
|
end
|
||||||
|
assert_match 'expecting <"PostSerializer"> but rendering with <["ProfileSerializer"]>', e.message
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def test_raises_argument_error_when_asserting_with_invalid_object
|
||||||
|
get :render_using_serializer
|
||||||
|
e = assert_raise ArgumentError do
|
||||||
|
assert_serializer Hash
|
||||||
|
end
|
||||||
|
assert_match 'assert_serializer only accepts a String, Symbol, Regexp, ActiveModel::Serializer, or nil', e.message
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_does_not_overwrite_notification_subscriptions
|
||||||
|
get :render_template
|
||||||
|
assert_template "template"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
94
test/integration/active_record/active_record_test.rb
Normal file
94
test/integration/active_record/active_record_test.rb
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
require 'fixtures/active_record'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class ActiveRecordTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@post = ARPost.first
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_serialization_embedding_objects
|
||||||
|
post_serializer = ARPostSerializer.new(@post)
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'ar_post' => {
|
||||||
|
title: 'New post', body: 'A body!!!',
|
||||||
|
ar_comments: [{ body: 'what a dumb post', ar_tags: [{ name: 'happy' }, { name: 'whiny' }] },
|
||||||
|
{ body: 'i liked it', ar_tags: [{:name=>"happy"}, {:name=>"short"}] }],
|
||||||
|
ar_tags: [{ name: 'short' }, { name: 'whiny' }],
|
||||||
|
ar_section: { 'name' => 'ruby' }
|
||||||
|
}
|
||||||
|
}, post_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_serialization_embedding_ids
|
||||||
|
post_serializer = ARPostSerializer.new(@post)
|
||||||
|
|
||||||
|
embed(ARPostSerializer, embed: :ids) do
|
||||||
|
assert_equal({
|
||||||
|
'ar_post' => {
|
||||||
|
title: 'New post', body: 'A body!!!',
|
||||||
|
'ar_comment_ids' => [1, 2],
|
||||||
|
'ar_tag_ids' => [1, 2],
|
||||||
|
'ar_section_id' => 1
|
||||||
|
}
|
||||||
|
}, post_serializer.as_json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_serialization_embedding_ids_including_in_root
|
||||||
|
post_serializer = ARPostSerializer.new(@post)
|
||||||
|
|
||||||
|
embed(ARPostSerializer, embed: :ids, embed_in_root: true) do
|
||||||
|
embed(ARCommentSerializer, embed: :ids, embed_in_root: true) do
|
||||||
|
assert_equal({
|
||||||
|
'ar_post' => {
|
||||||
|
title: 'New post', body: 'A body!!!',
|
||||||
|
'ar_comment_ids' => [1, 2],
|
||||||
|
'ar_tag_ids' => [1, 2],
|
||||||
|
'ar_section_id' => 1
|
||||||
|
},
|
||||||
|
'ar_comments' => [{ body: 'what a dumb post', 'ar_tag_ids' => [3, 2] },
|
||||||
|
{ body: 'i liked it', 'ar_tag_ids' => [3, 1] }],
|
||||||
|
'ar_tags' => [{ name: 'happy' }, { name: 'whiny' }, { name: 'short' }],
|
||||||
|
'ar_sections' => [{ 'name' => 'ruby' }]
|
||||||
|
}, post_serializer.as_json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_serialization_embedding_ids_in_common_root_key
|
||||||
|
post_serializer = AREmbeddedSerializer.new(@post)
|
||||||
|
|
||||||
|
embed(AREmbeddedSerializer, embed: :ids, embed_in_root: true, embed_in_root_key: :linked) do
|
||||||
|
embed(ARCommentSerializer, embed: :ids, embed_in_root: true, embed_in_root_key: :linked) do
|
||||||
|
assert_equal({
|
||||||
|
'ar_tags' => [{ name: 'short' },
|
||||||
|
{ name: 'whiny' },
|
||||||
|
{ name: 'happy' }],
|
||||||
|
'ar_comments' => [{ body: 'what a dumb post', 'ar_tag_ids' => [3, 2] },
|
||||||
|
{ body: 'i liked it', 'ar_tag_ids' => [3, 1] }]
|
||||||
|
}, post_serializer.as_json[:linked])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def embed(serializer_class, options = {})
|
||||||
|
old_assocs = Hash[serializer_class._associations.to_a.map { |(name, association)| [name, association.dup] }]
|
||||||
|
|
||||||
|
serializer_class._associations.each_value do |association|
|
||||||
|
association.embed = options[:embed]
|
||||||
|
association.embed_in_root = options[:embed_in_root]
|
||||||
|
association.embed_in_root_key = options[:embed_in_root_key]
|
||||||
|
end
|
||||||
|
|
||||||
|
yield
|
||||||
|
ensure
|
||||||
|
serializer_class._associations = old_assocs
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
26
test/integration/generators/resource_generator_test.rb
Normal file
26
test/integration/generators/resource_generator_test.rb
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
require 'rails'
|
||||||
|
require 'active_model/serializer/railtie'
|
||||||
|
require 'test_app'
|
||||||
|
|
||||||
|
class ResourceGeneratorTest < Rails::Generators::TestCase
|
||||||
|
destination File.expand_path('../../../tmp', __FILE__)
|
||||||
|
setup :prepare_destination, :copy_routes
|
||||||
|
|
||||||
|
tests Rails::Generators::ResourceGenerator
|
||||||
|
arguments %w(account)
|
||||||
|
|
||||||
|
def test_serializer_file_is_generated
|
||||||
|
run_generator
|
||||||
|
|
||||||
|
assert_file 'app/serializers/account_serializer.rb', /class AccountSerializer < ActiveModel::Serializer/
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def copy_routes
|
||||||
|
config_dir = File.join(destination_root, 'config')
|
||||||
|
FileUtils.mkdir_p(config_dir)
|
||||||
|
File.write(File.join(config_dir, 'routes.rb'), 'Rails.application.routes.draw { }')
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
require 'rails'
|
||||||
|
require 'active_model/serializer/railtie'
|
||||||
|
require 'test_app'
|
||||||
|
|
||||||
|
class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase
|
||||||
|
destination File.expand_path('../../../tmp', __FILE__)
|
||||||
|
setup :prepare_destination
|
||||||
|
|
||||||
|
tests Rails::Generators::ScaffoldControllerGenerator
|
||||||
|
arguments %w(account name:string description:text business:references)
|
||||||
|
|
||||||
|
def test_generated_controller
|
||||||
|
return true if Rails::VERSION::MAJOR < 4
|
||||||
|
|
||||||
|
run_generator
|
||||||
|
|
||||||
|
assert_file 'app/controllers/accounts_controller.rb' do |content|
|
||||||
|
assert_instance_method :index, content do |m|
|
||||||
|
assert_match /@accounts = Account\.all/, m
|
||||||
|
assert_match /format.html/, m
|
||||||
|
assert_match /format.json \{ render json: @accounts \}/, m
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_instance_method :show, content do |m|
|
||||||
|
assert_match /format.html/, m
|
||||||
|
assert_match /format.json \{ render json: @account \}/, m
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_instance_method :new, content do |m|
|
||||||
|
assert_match /@account = Account\.new/, m
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_instance_method :edit, content do |m|
|
||||||
|
assert m.blank?
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_instance_method :create, content do |m|
|
||||||
|
assert_match /@account = Account\.new\(account_params\)/, m
|
||||||
|
assert_match /@account\.save/, m
|
||||||
|
assert_match /format\.html \{ redirect_to @account, notice: 'Account was successfully created\.' \}/, m
|
||||||
|
assert_match /format\.json \{ render json: @account, status: :created \}/, m
|
||||||
|
assert_match /format\.html \{ render action: 'new' \}/, m
|
||||||
|
assert_match /format\.json \{ render json: @account\.errors, status: :unprocessable_entity \}/, m
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_instance_method :update, content do |m|
|
||||||
|
assert_match /format\.html \{ redirect_to @account, notice: 'Account was successfully updated\.' \}/, m
|
||||||
|
assert_match /format\.json \{ head :no_content \}/, m
|
||||||
|
assert_match /format\.html \{ render action: 'edit' \}/, m
|
||||||
|
assert_match /format\.json \{ render json: @account.errors, status: :unprocessable_entity \}/, m
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_instance_method :destroy, content do |m|
|
||||||
|
assert_match /@account\.destroy/, m
|
||||||
|
assert_match /format\.html { redirect_to accounts_url \}/, m
|
||||||
|
assert_match /format\.json \{ head :no_content \}/, m
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_match(/def account_params/, content)
|
||||||
|
assert_match(/params\.require\(:account\)\.permit\(:name, :description, :business_id\)/, content)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
41
test/integration/generators/serializer_generator_test.rb
Normal file
41
test/integration/generators/serializer_generator_test.rb
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
require 'rails'
|
||||||
|
require 'active_model/serializer/railtie'
|
||||||
|
require 'test_app'
|
||||||
|
|
||||||
|
class SerializerGeneratorTest < Rails::Generators::TestCase
|
||||||
|
destination File.expand_path('../../../tmp', __FILE__)
|
||||||
|
setup :prepare_destination
|
||||||
|
|
||||||
|
tests Rails::Generators::SerializerGenerator
|
||||||
|
arguments %w(account name:string description:text business:references)
|
||||||
|
|
||||||
|
def test_generates_a_serializer_with_attributes_and_associations
|
||||||
|
run_generator
|
||||||
|
assert_file 'app/serializers/account_serializer.rb', /class AccountSerializer < ActiveModel::Serializer/ do |serializer|
|
||||||
|
assert_match(/attributes :id, :name, :description/, serializer)
|
||||||
|
assert_match(/has_one :business/, serializer)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_generates_a_namespaced_serializer
|
||||||
|
run_generator ['admin/account']
|
||||||
|
assert_file 'app/serializers/admin/account_serializer.rb', /class Admin::AccountSerializer < ActiveModel::Serializer/
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_uses_application_serializer_if_one_exists
|
||||||
|
Object.const_set(:ApplicationSerializer, Class.new)
|
||||||
|
run_generator
|
||||||
|
assert_file 'app/serializers/account_serializer.rb', /class AccountSerializer < ApplicationSerializer/
|
||||||
|
ensure
|
||||||
|
Object.send :remove_const, :ApplicationSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_uses_given_parent
|
||||||
|
Object.const_set(:ApplicationSerializer, Class.new)
|
||||||
|
run_generator ['Account', '--parent=MySerializer']
|
||||||
|
assert_file 'app/serializers/account_serializer.rb', /class AccountSerializer < MySerializer/
|
||||||
|
ensure
|
||||||
|
Object.send :remove_const, :ApplicationSerializer
|
||||||
|
end
|
||||||
|
end
|
||||||
14
test/test_app.rb
Normal file
14
test/test_app.rb
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
class TestApp < Rails::Application
|
||||||
|
if Rails.version.to_s.first >= '4'
|
||||||
|
config.eager_load = false
|
||||||
|
config.secret_key_base = 'abc123'
|
||||||
|
end
|
||||||
|
config.after_initialize do
|
||||||
|
Rails.application.routes.default_url_options = { host: 'http://example.com' }
|
||||||
|
end
|
||||||
|
|
||||||
|
# Set up a logger to avoid creating a log directory on every run.
|
||||||
|
config.logger = Logger.new(nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
TestApp.initialize!
|
||||||
24
test/test_helper.rb
Normal file
24
test/test_helper.rb
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
require 'bundler/setup'
|
||||||
|
require 'minitest/autorun'
|
||||||
|
require 'active_model_serializers'
|
||||||
|
require 'fixtures/poro'
|
||||||
|
|
||||||
|
# Ensure backward compatibility with Minitest 4
|
||||||
|
Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test)
|
||||||
|
|
||||||
|
module TestHelper
|
||||||
|
Routes = ActionDispatch::Routing::RouteSet.new
|
||||||
|
Routes.draw do
|
||||||
|
get ':controller(/:action(/:id))'
|
||||||
|
get ':controller(/:action)'
|
||||||
|
end
|
||||||
|
|
||||||
|
ActionController::Base.send :include, Routes.url_helpers
|
||||||
|
ActionController::Base.send :include, ActionController::Serialization
|
||||||
|
end
|
||||||
|
|
||||||
|
ActionController::TestCase.class_eval do
|
||||||
|
def setup
|
||||||
|
@routes = TestHelper::Routes
|
||||||
|
end
|
||||||
|
end
|
||||||
18
test/unit/active_model/array_serializer/except_test.rb
Normal file
18
test/unit/active_model/array_serializer/except_test.rb
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class ArraySerializer
|
||||||
|
class ExceptTest < Minitest::Test
|
||||||
|
def test_array_serializer_pass_except_to_items_serializers
|
||||||
|
array = [Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' }),
|
||||||
|
Profile.new({ name: 'Name 2', description: 'Description 2', comments: 'Comments 2' })]
|
||||||
|
serializer = ArraySerializer.new(array, except: [:description])
|
||||||
|
|
||||||
|
expected = [{ name: 'Name 1' },
|
||||||
|
{ name: 'Name 2' }]
|
||||||
|
|
||||||
|
assert_equal expected, serializer.serializable_array
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
18
test/unit/active_model/array_serializer/key_format_test.rb
Normal file
18
test/unit/active_model/array_serializer/key_format_test.rb
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class ArraySerializer
|
||||||
|
class KeyFormatTest < Minitest::Test
|
||||||
|
def test_array_serializer_pass_options_to_items_serializers
|
||||||
|
array = [WebLog.new({ name: 'Name 1', display_name: 'Display Name 1'}),
|
||||||
|
WebLog.new({ name: 'Name 2', display_name: 'Display Name 2'})]
|
||||||
|
serializer = ArraySerializer.new(array, key_format: :lower_camel)
|
||||||
|
|
||||||
|
expected = [{ name: 'Name 1', displayName: 'Display Name 1' },
|
||||||
|
{ name: 'Name 2', displayName: 'Display Name 2' }]
|
||||||
|
|
||||||
|
assert_equal expected, serializer.serializable_array
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
53
test/unit/active_model/array_serializer/meta_test.rb
Normal file
53
test/unit/active_model/array_serializer/meta_test.rb
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
require 'active_model/serializer'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class ArraySerializer
|
||||||
|
class MetaTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@profile1 = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||||
|
@profile2 = Profile.new({ name: 'Name 2', description: 'Description 2', comments: 'Comments 2' })
|
||||||
|
@serializer = ArraySerializer.new([@profile1, @profile2], root: 'profiles')
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_meta
|
||||||
|
@serializer.meta = { total: 10 }
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'profiles' => [
|
||||||
|
{
|
||||||
|
name: 'Name 1',
|
||||||
|
description: 'Description 1'
|
||||||
|
}, {
|
||||||
|
name: 'Name 2',
|
||||||
|
description: 'Description 2'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
meta: {
|
||||||
|
total: 10
|
||||||
|
}
|
||||||
|
}, @serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_meta_using_meta_key
|
||||||
|
@serializer.meta_key = :my_meta
|
||||||
|
@serializer.meta = { total: 10 }
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'profiles' => [
|
||||||
|
{
|
||||||
|
name: 'Name 1',
|
||||||
|
description: 'Description 1'
|
||||||
|
}, {
|
||||||
|
name: 'Name 2',
|
||||||
|
description: 'Description 2'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
my_meta: {
|
||||||
|
total: 10
|
||||||
|
}
|
||||||
|
}, @serializer.as_json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
18
test/unit/active_model/array_serializer/only_test.rb
Normal file
18
test/unit/active_model/array_serializer/only_test.rb
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class ArraySerializer
|
||||||
|
class OnlyTest < Minitest::Test
|
||||||
|
def test_array_serializer_pass_only_to_items_serializers
|
||||||
|
array = [Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' }),
|
||||||
|
Profile.new({ name: 'Name 2', description: 'Description 2', comments: 'Comments 2' })]
|
||||||
|
serializer = ArraySerializer.new(array, only: [:name])
|
||||||
|
|
||||||
|
expected = [{ name: 'Name 1' },
|
||||||
|
{ name: 'Name 2' }]
|
||||||
|
|
||||||
|
assert_equal expected, serializer.serializable_array
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
16
test/unit/active_model/array_serializer/options_test.rb
Normal file
16
test/unit/active_model/array_serializer/options_test.rb
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class ArraySerializer
|
||||||
|
class OptionsTest < Minitest::Test
|
||||||
|
def test_custom_options_are_accessible_from_serializer
|
||||||
|
|
||||||
|
array = [Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' }),
|
||||||
|
Profile.new({ name: 'Name 2', description: 'Description 2', comments: 'Comments 2' })]
|
||||||
|
serializer = ArraySerializer.new(array, only: [:name], context: {foo: :bar})
|
||||||
|
|
||||||
|
assert_equal({foo: :bar}, serializer.context)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
102
test/unit/active_model/array_serializer/root_test.rb
Normal file
102
test/unit/active_model/array_serializer/root_test.rb
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class ArraySerializer
|
||||||
|
class RootAsOptionTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@old_root = ArraySerializer._root
|
||||||
|
@profile1 = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||||
|
@profile2 = Profile.new({ name: 'Name 2', description: 'Description 2', comments: 'Comments 2' })
|
||||||
|
@serializer = ArraySerializer.new([@profile1, @profile2], root: :initialize)
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
ArraySerializer._root = @old_root
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_root_is_not_displayed_using_serializable_array
|
||||||
|
assert_equal([
|
||||||
|
{ name: 'Name 1', description: 'Description 1' },
|
||||||
|
{ name: 'Name 2', description: 'Description 2' }
|
||||||
|
], @serializer.serializable_array)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_root_using_as_json
|
||||||
|
assert_equal({
|
||||||
|
initialize: [
|
||||||
|
{ name: 'Name 1', description: 'Description 1' },
|
||||||
|
{ name: 'Name 2', description: 'Description 2' }
|
||||||
|
]
|
||||||
|
}, @serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_root_as_argument_takes_precedence
|
||||||
|
assert_equal({
|
||||||
|
argument: [
|
||||||
|
{ name: 'Name 1', description: 'Description 1' },
|
||||||
|
{ name: 'Name 2', description: 'Description 2' }
|
||||||
|
]
|
||||||
|
}, @serializer.as_json(root: :argument))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_using_false_root_in_initialize_takes_precedence
|
||||||
|
ArraySerializer._root = 'root'
|
||||||
|
@serializer = ArraySerializer.new([@profile1, @profile2], root: false)
|
||||||
|
|
||||||
|
assert_equal([
|
||||||
|
{ name: 'Name 1', description: 'Description 1' },
|
||||||
|
{ name: 'Name 2', description: 'Description 2' }
|
||||||
|
], @serializer.as_json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class RootInSerializerTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@old_root = ArraySerializer._root
|
||||||
|
ArraySerializer._root = :in_serializer
|
||||||
|
@profile1 = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||||
|
@profile2 = Profile.new({ name: 'Name 2', description: 'Description 2', comments: 'Comments 2' })
|
||||||
|
@serializer = ArraySerializer.new([@profile1, @profile2])
|
||||||
|
@rooted_serializer = ArraySerializer.new([@profile1, @profile2], root: :initialize)
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
ArraySerializer._root = @old_root
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_root_is_not_displayed_using_serializable_hash
|
||||||
|
assert_equal([
|
||||||
|
{ name: 'Name 1', description: 'Description 1' },
|
||||||
|
{ name: 'Name 2', description: 'Description 2' }
|
||||||
|
], @serializer.serializable_array)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_root_using_as_json
|
||||||
|
assert_equal({
|
||||||
|
in_serializer: [
|
||||||
|
{ name: 'Name 1', description: 'Description 1' },
|
||||||
|
{ name: 'Name 2', description: 'Description 2' }
|
||||||
|
]
|
||||||
|
}, @serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_root_in_initializer_takes_precedence
|
||||||
|
assert_equal({
|
||||||
|
initialize: [
|
||||||
|
{ name: 'Name 1', description: 'Description 1' },
|
||||||
|
{ name: 'Name 2', description: 'Description 2' }
|
||||||
|
]
|
||||||
|
}, @rooted_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_root_as_argument_takes_precedence
|
||||||
|
assert_equal({
|
||||||
|
argument: [
|
||||||
|
{ name: 'Name 1', description: 'Description 1' },
|
||||||
|
{ name: 'Name 2', description: 'Description 2' }
|
||||||
|
]
|
||||||
|
}, @rooted_serializer.as_json(root: :argument))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
24
test/unit/active_model/array_serializer/scope_test.rb
Normal file
24
test/unit/active_model/array_serializer/scope_test.rb
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class ArraySerializer
|
||||||
|
class ScopeTest < Minitest::Test
|
||||||
|
def test_array_serializer_pass_options_to_items_serializers
|
||||||
|
array = [Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' }),
|
||||||
|
Profile.new({ name: 'Name 2', description: 'Description 2', comments: 'Comments 2' })]
|
||||||
|
serializer = ArraySerializer.new(array, scope: current_user)
|
||||||
|
|
||||||
|
expected = [{ name: 'Name 1', description: 'Description 1 - user' },
|
||||||
|
{ name: 'Name 2', description: 'Description 2 - user' }]
|
||||||
|
|
||||||
|
assert_equal expected, serializer.serializable_array
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def current_user
|
||||||
|
'user'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
216
test/unit/active_model/array_serializer/serialization_test.rb
Normal file
216
test/unit/active_model/array_serializer/serialization_test.rb
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class ArraySerializer
|
||||||
|
class BasicObjectsSerializationTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
array = [1, 2, 3]
|
||||||
|
@serializer = Serializer.serializer_for(array).new(array)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_serializer_for_array_returns_appropriate_type
|
||||||
|
assert_kind_of ActiveModel::ArraySerializer, @serializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_array_serializer_serializes_simple_objects
|
||||||
|
assert_equal [1, 2, 3], @serializer.serializable_array
|
||||||
|
assert_equal [1, 2, 3], @serializer.as_json
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class CustomArraySerializerSupport < Minitest::Test
|
||||||
|
def setup
|
||||||
|
Object.const_set(:ArraySerializer, Class.new)
|
||||||
|
|
||||||
|
array = [1, 2, 3]
|
||||||
|
@serializer_class = Serializer.serializer_for(array)
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
Object.send(:remove_const, :ArraySerializer)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_serializer_for_array_returns_appropriate_type
|
||||||
|
assert_equal ::ArraySerializer, @serializer_class
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class CustomSerializerClassTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
Object.const_set(:CustomSerializer, Class.new)
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
Object.send(:remove_const, :CustomSerializer)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_serializer_for_array_returns_appropriate_type
|
||||||
|
object = {}
|
||||||
|
def object.serializer_class; CustomSerializer; end
|
||||||
|
|
||||||
|
assert_equal CustomSerializer, Serializer.serializer_for(object)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ModelSerializationTest < Minitest::Test
|
||||||
|
def test_array_serializer_serializes_models
|
||||||
|
array = [Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' }),
|
||||||
|
Profile.new({ name: 'Name 2', description: 'Description 2', comments: 'Comments 2' })]
|
||||||
|
serializer = ArraySerializer.new(array)
|
||||||
|
|
||||||
|
expected = [{ name: 'Name 1', description: 'Description 1' },
|
||||||
|
{ name: 'Name 2', description: 'Description 2' }]
|
||||||
|
|
||||||
|
assert_equal expected, serializer.serializable_array
|
||||||
|
assert_equal expected, serializer.as_json
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_array_serializers_each_serializer
|
||||||
|
array = [::Model.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' }),
|
||||||
|
::Model.new({ name: 'Name 2', description: 'Description 2', comments: 'Comments 2' })]
|
||||||
|
serializer = ArraySerializer.new(array, each_serializer: ProfileSerializer)
|
||||||
|
|
||||||
|
expected = [{ name: 'Name 1', description: 'Description 1' },
|
||||||
|
{ name: 'Name 2', description: 'Description 2' }]
|
||||||
|
|
||||||
|
assert_equal expected, serializer.serializable_array
|
||||||
|
assert_equal expected, serializer.as_json
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associated_objects_of_multiple_instances_embedded_in_root
|
||||||
|
@association = PostSerializer._associations[:comments]
|
||||||
|
@old_association = @association.dup
|
||||||
|
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
|
||||||
|
@post1 = Post.new({ title: 'Title 1', body: 'Body 1', date: '1/1/2000' })
|
||||||
|
@post2 = Post.new({ title: 'Title 2', body: 'Body 2', date: '1/1/2000' })
|
||||||
|
|
||||||
|
class << @post2
|
||||||
|
attr_writer :comments
|
||||||
|
end
|
||||||
|
|
||||||
|
@post2.comments = [
|
||||||
|
Comment.new(content: 'C3'),
|
||||||
|
Comment.new(content: 'C4')
|
||||||
|
]
|
||||||
|
|
||||||
|
@serializer = ArraySerializer.new([@post1, @post2], root: :posts)
|
||||||
|
assert_equal({
|
||||||
|
posts: [
|
||||||
|
{title: "Title 1", body: "Body 1", "comment_ids" => @post1.comments.map(&:object_id) },
|
||||||
|
{title: "Title 2", body: "Body 2", "comment_ids" => @post2.comments.map(&:object_id) }
|
||||||
|
],
|
||||||
|
'comments' => [
|
||||||
|
{content: "C1"},
|
||||||
|
{content: "C2"},
|
||||||
|
{content: "C3"},
|
||||||
|
{content: "C4"}
|
||||||
|
]
|
||||||
|
}, @serializer.as_json)
|
||||||
|
ensure
|
||||||
|
PostSerializer._associations[:comments] = @old_association
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_embed_object_for_has_one_association_with_nil_value
|
||||||
|
@association = UserSerializer._associations[:profile]
|
||||||
|
@old_association = @association.dup
|
||||||
|
|
||||||
|
@association.embed = :objects
|
||||||
|
|
||||||
|
@user1 = User.new({ name: 'User 1', email: 'email1@server.com' })
|
||||||
|
@user2 = User.new({ name: 'User 2', email: 'email2@server.com' })
|
||||||
|
|
||||||
|
class << @user1
|
||||||
|
def profile
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class << @user2
|
||||||
|
def profile
|
||||||
|
@profile ||= Profile.new(name: 'Name 1', description: 'Desc 1')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@serializer = ArraySerializer.new([@user1, @user2]) #, root: :posts)
|
||||||
|
assert_equal([
|
||||||
|
{ name: "User 1", email: "email1@server.com", profile: nil },
|
||||||
|
{ name: "User 2", email: "email2@server.com", profile: { name: 'Name 1', description: 'Desc 1' } }
|
||||||
|
], @serializer.as_json)
|
||||||
|
ensure
|
||||||
|
UserSerializer._associations[:profile] = @old_association
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_embed_object_in_root_for_has_one_association_with_nil_value
|
||||||
|
@association = UserSerializer._associations[:profile]
|
||||||
|
@old_association = @association.dup
|
||||||
|
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
|
||||||
|
@user1 = User.new({ name: 'User 1', email: 'email1@server.com' })
|
||||||
|
@user2 = User.new({ name: 'User 2', email: 'email2@server.com' })
|
||||||
|
|
||||||
|
class << @user1
|
||||||
|
def profile
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class << @user2
|
||||||
|
def profile
|
||||||
|
@profile ||= Profile.new(name: 'Name 1', description: 'Desc 1')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@serializer = ArraySerializer.new([@user1, @user2], root: :users)
|
||||||
|
assert_equal({
|
||||||
|
users: [
|
||||||
|
{ name: "User 1", email: "email1@server.com", 'profile_id' => nil },
|
||||||
|
{ name: "User 2", email: "email2@server.com", 'profile_id' => @user2.profile.object_id }
|
||||||
|
],
|
||||||
|
'profiles' => [
|
||||||
|
{ name: 'Name 1', description: 'Desc 1' }
|
||||||
|
]
|
||||||
|
}, @serializer.as_json)
|
||||||
|
ensure
|
||||||
|
UserSerializer._associations[:profile] = @old_association
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_embed_object_in_root_for_has_one_association_with_all_nil_values
|
||||||
|
@association = UserSerializer._associations[:profile]
|
||||||
|
@old_association = @association.dup
|
||||||
|
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
|
||||||
|
@user1 = User.new({ name: 'User 1', email: 'email1@server.com' })
|
||||||
|
@user2 = User.new({ name: 'User 2', email: 'email2@server.com' })
|
||||||
|
|
||||||
|
class << @user1
|
||||||
|
def profile
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class << @user2
|
||||||
|
def profile
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@serializer = ArraySerializer.new([@user1, @user2], root: :users)
|
||||||
|
assert_equal({
|
||||||
|
users: [
|
||||||
|
{ name: "User 1", email: "email1@server.com", 'profile_id' => nil },
|
||||||
|
{ name: "User 2", email: "email2@server.com", 'profile_id' => nil }
|
||||||
|
]
|
||||||
|
}, @serializer.as_json)
|
||||||
|
ensure
|
||||||
|
UserSerializer._associations[:profile] = @old_association
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
13
test/unit/active_model/default_serializer_test.rb
Normal file
13
test/unit/active_model/default_serializer_test.rb
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class DefaultSerializer
|
||||||
|
class Test < Minitest::Test
|
||||||
|
def test_serialize_objects
|
||||||
|
assert_equal(nil, DefaultSerializer.new(nil).serializable_object)
|
||||||
|
assert_equal(1, DefaultSerializer.new(1).serializable_object)
|
||||||
|
assert_equal('hi', DefaultSerializer.new('hi').serializable_object)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class Association
|
||||||
|
class BuildSerializerTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@association = Association::HasOne.new('post', serializer: PostSerializer)
|
||||||
|
@post = Post.new({ title: 'Title 1', body: 'Body 1', date: '1/1/2000' })
|
||||||
|
@user = User.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_build_serializer_for_array_called_twice
|
||||||
|
2.times do
|
||||||
|
serializer = @association.build_serializer(@post)
|
||||||
|
assert_instance_of(PostSerializer, serializer)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_build_serializer_from_in_a_namespace
|
||||||
|
assoc = Association::HasOne.new('profile')
|
||||||
|
serializer = TestNamespace::UserSerializer.new(@user).build_serializer(assoc)
|
||||||
|
|
||||||
|
assert_instance_of(TestNamespace::ProfileSerializer, serializer)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_build_serializer_with_prefix
|
||||||
|
assoc = Association::HasOne.new('profile', prefix: :short)
|
||||||
|
serializer = UserSerializer.new(@user).build_serializer(assoc)
|
||||||
|
|
||||||
|
assert_instance_of(ShortProfileSerializer, serializer)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
49
test/unit/active_model/serializer/associations_test.rb
Normal file
49
test/unit/active_model/serializer/associations_test.rb
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class AssociationsTest < Minitest::Test
|
||||||
|
def test_associations_inheritance
|
||||||
|
inherited_serializer_klass = Class.new(PostSerializer) do
|
||||||
|
has_many :users
|
||||||
|
end
|
||||||
|
another_inherited_serializer_klass = Class.new(PostSerializer)
|
||||||
|
|
||||||
|
assert_equal([:comments, :users],
|
||||||
|
inherited_serializer_klass._associations.keys)
|
||||||
|
assert_equal([:comments],
|
||||||
|
another_inherited_serializer_klass._associations.keys)
|
||||||
|
end
|
||||||
|
def test_multiple_nested_associations
|
||||||
|
parent = SelfReferencingUserParent.new(name: "The Parent")
|
||||||
|
child = SelfReferencingUser.new(name: "The child", parent: parent)
|
||||||
|
self_referencing_user_serializer = SelfReferencingUserSerializer.new(child)
|
||||||
|
result = self_referencing_user_serializer.as_json
|
||||||
|
expected_result = {
|
||||||
|
"self_referencing_user"=>{
|
||||||
|
:name=>"The child",
|
||||||
|
"type_id"=>child.type.object_id,
|
||||||
|
"parent_id"=>child.parent.object_id
|
||||||
|
|
||||||
|
},
|
||||||
|
"types"=>[
|
||||||
|
{
|
||||||
|
:name=>"N1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
:name=>"N2",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parents"=>[
|
||||||
|
{
|
||||||
|
:name=>"N1",
|
||||||
|
"type_id"=>child.parent.type.object_id,
|
||||||
|
"parent_id"=>nil
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
assert_equal(expected_result, result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
57
test/unit/active_model/serializer/attributes_test.rb
Normal file
57
test/unit/active_model/serializer/attributes_test.rb
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class AttributesTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||||
|
@profile_serializer = ProfileSerializer.new(@profile)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_attributes_definition
|
||||||
|
assert_equal([:name, :description],
|
||||||
|
@profile_serializer.class._attributes)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_attributes_serialization_using_serializable_hash
|
||||||
|
assert_equal({
|
||||||
|
name: 'Name 1', description: 'Description 1'
|
||||||
|
}, @profile_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_attributes_serialization_using_as_json
|
||||||
|
assert_equal({
|
||||||
|
'profile' => { name: 'Name 1', description: 'Description 1' }
|
||||||
|
}, @profile_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_attributes_inheritance
|
||||||
|
inherited_serializer_klass = Class.new(ProfileSerializer) do
|
||||||
|
attributes :comments
|
||||||
|
end
|
||||||
|
another_inherited_serializer_klass = Class.new(ProfileSerializer)
|
||||||
|
|
||||||
|
assert_equal([:name, :description, :comments],
|
||||||
|
inherited_serializer_klass._attributes)
|
||||||
|
assert_equal([:name, :description],
|
||||||
|
another_inherited_serializer_klass._attributes)
|
||||||
|
end
|
||||||
|
|
||||||
|
def tests_query_attributes_strip_question_mark
|
||||||
|
model = Class.new(::Model) do
|
||||||
|
def strip?
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
serializer = Class.new(ActiveModel::Serializer) do
|
||||||
|
attributes :strip?
|
||||||
|
end
|
||||||
|
|
||||||
|
actual = serializer.new(model.new).as_json
|
||||||
|
|
||||||
|
assert_equal({ strip: true }, actual)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
91
test/unit/active_model/serializer/config_test.rb
Normal file
91
test/unit/active_model/serializer/config_test.rb
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class Config
|
||||||
|
class Test < Minitest::Test
|
||||||
|
def test_config_const_is_an_instance_of_config
|
||||||
|
assert_kind_of Config, CONFIG
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_config_instance
|
||||||
|
config = Config.new
|
||||||
|
config.setting1 = 'value1'
|
||||||
|
|
||||||
|
assert_equal 'value1', config.setting1
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_each_config
|
||||||
|
config = Config.new
|
||||||
|
config.setting1 = 'value1'
|
||||||
|
config.setting2 = 'value2'
|
||||||
|
|
||||||
|
actual = {}
|
||||||
|
|
||||||
|
config.each do |k, v|
|
||||||
|
actual[k] = v
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal({ 'setting1' => 'value1', 'setting2' => 'value2' }, actual)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ConfigTest < Minitest::Test
|
||||||
|
def test_setup
|
||||||
|
Serializer.setup do |config|
|
||||||
|
config.a = 'v1'
|
||||||
|
config.b = 'v2'
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal 'v1', CONFIG.a
|
||||||
|
assert_equal 'v2', CONFIG.b
|
||||||
|
ensure
|
||||||
|
CONFIG.clear
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_config_accessors
|
||||||
|
Serializer.setup do |config|
|
||||||
|
config.foo = 'v1'
|
||||||
|
config.bar = 'v2'
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal 'v1', CONFIG.foo
|
||||||
|
assert_equal 'v2', CONFIG.bar
|
||||||
|
ensure
|
||||||
|
CONFIG.clear
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_acessor_when_nil
|
||||||
|
assert_nil CONFIG.foo
|
||||||
|
CONFIG.foo = 1
|
||||||
|
assert_equal 1, CONFIG.foo
|
||||||
|
assert_nil CONFIG.bar
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ApplyConfigTest < Minitest::Test
|
||||||
|
def test_apply_config_to_associations
|
||||||
|
CONFIG.embed = :ids
|
||||||
|
CONFIG.embed_in_root = true
|
||||||
|
CONFIG.key_format = :lower_camel
|
||||||
|
|
||||||
|
association = PostSerializer._associations[:comments]
|
||||||
|
old_association = association.dup
|
||||||
|
|
||||||
|
association.send :initialize, association.name, association.options
|
||||||
|
|
||||||
|
assert association.embed_ids?
|
||||||
|
assert !association.embed_objects?
|
||||||
|
assert association.embed_in_root
|
||||||
|
assert_equal :lower_camel, association.key_format
|
||||||
|
assert_equal 'post', PostSerializer.root_name
|
||||||
|
CONFIG.plural_default_root = true
|
||||||
|
assert_equal 'posts', PostSerializer.root_name
|
||||||
|
ensure
|
||||||
|
PostSerializer._associations[:comments] = old_association
|
||||||
|
CONFIG.clear
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
69
test/unit/active_model/serializer/filter_test.rb
Normal file
69
test/unit/active_model/serializer/filter_test.rb
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class FilterOptionsTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_only_option
|
||||||
|
@profile_serializer = ProfileSerializer.new(@profile, only: :name)
|
||||||
|
assert_equal({
|
||||||
|
'profile' => { name: 'Name 1' }
|
||||||
|
}, @profile_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_except_option
|
||||||
|
@profile_serializer = ProfileSerializer.new(@profile, except: :comments)
|
||||||
|
assert_equal({
|
||||||
|
'profile' => { name: 'Name 1', description: 'Description 1' }
|
||||||
|
}, @profile_serializer.as_json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class FilterAttributesTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||||
|
@profile_serializer = ProfileSerializer.new(@profile)
|
||||||
|
@profile_serializer.instance_eval do
|
||||||
|
def filter(keys)
|
||||||
|
keys - [:description]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_filtered_attributes_serialization
|
||||||
|
assert_equal({
|
||||||
|
'profile' => { name: 'Name 1' }
|
||||||
|
}, @profile_serializer.as_json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class FilterAssociationsTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@association = PostSerializer._associations[:comments]
|
||||||
|
@old_association = @association.dup
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
@post = Post.new({ title: 'Title 1', body: 'Body 1', date: '1/1/2000' })
|
||||||
|
@post_serializer = PostSerializer.new(@post)
|
||||||
|
@post_serializer.instance_eval do
|
||||||
|
def filter(keys)
|
||||||
|
keys - [:body, :comments]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
PostSerializer._associations[:comments] = @old_association
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_filtered_associations_serialization
|
||||||
|
assert_equal({
|
||||||
|
'post' => { title: 'Title 1' }
|
||||||
|
}, @post_serializer.as_json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
189
test/unit/active_model/serializer/has_many_polymorphic_test.rb
Normal file
189
test/unit/active_model/serializer/has_many_polymorphic_test.rb
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class HasManyPolymorphicTest < ActiveModel::TestCase
|
||||||
|
def setup
|
||||||
|
@association = MailSerializer._associations[:attachments]
|
||||||
|
@old_association = @association.dup
|
||||||
|
|
||||||
|
@mail = Mail.new({ body: 'Body 1' })
|
||||||
|
@mail_serializer = MailSerializer.new(@mail)
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
MailSerializer._associations[:attachments] = @old_association
|
||||||
|
end
|
||||||
|
|
||||||
|
def model_name(object)
|
||||||
|
object.class.to_s.demodulize.underscore.to_sym
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_definition
|
||||||
|
assert_equal 1, MailSerializer._associations.length
|
||||||
|
assert_kind_of Association::HasMany, @association
|
||||||
|
assert_equal true, @association.polymorphic
|
||||||
|
assert_equal 'attachments', @association.name
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_serialization_using_serializable_hash
|
||||||
|
@association.embed = :ids
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
body: 'Body 1',
|
||||||
|
'attachment_ids' => @mail.attachments.map do |c|
|
||||||
|
{ id: c.object_id, type: model_name(c) }
|
||||||
|
end
|
||||||
|
}, @mail_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_serialization_using_as_json
|
||||||
|
@association.embed = :ids
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'mail' => {
|
||||||
|
:body => 'Body 1',
|
||||||
|
'attachment_ids' => @mail.attachments.map do |c|
|
||||||
|
{ id: c.object_id, type: model_name(c) }
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}, @mail_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_serialization_using_serializable_hash_and_key_from_options
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.key = 'key'
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
body: 'Body 1',
|
||||||
|
'key' => @mail.attachments.map do |c|
|
||||||
|
{ id: c.object_id, type: model_name(c) }
|
||||||
|
end
|
||||||
|
}, @mail_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_objects_serialization_using_serializable_hash
|
||||||
|
@association.embed = :objects
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
body: 'Body 1',
|
||||||
|
:attachments => [
|
||||||
|
{ type: :image, image: { url: 'U1' }},
|
||||||
|
{ type: :video, video: { html: 'H1' }}
|
||||||
|
]
|
||||||
|
}, @mail_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_objects_serialization_using_as_json
|
||||||
|
@association.embed = :objects
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'mail' => {
|
||||||
|
body: 'Body 1',
|
||||||
|
attachments: [
|
||||||
|
{ type: :image, image: { url: 'U1' }},
|
||||||
|
{ type: :video, video: { html: 'H1' }}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}, @mail_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_nil_objects_serialization_using_as_json
|
||||||
|
@association.embed = :objects
|
||||||
|
@mail.instance_eval do
|
||||||
|
def attachments
|
||||||
|
[nil]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'mail' => {
|
||||||
|
:body => 'Body 1',
|
||||||
|
:attachments => [nil]
|
||||||
|
}
|
||||||
|
}, @mail_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_objects_serialization_using_serializable_hash_and_root_from_options
|
||||||
|
@association.embed = :objects
|
||||||
|
@association.embedded_key = 'root'
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
body: 'Body 1',
|
||||||
|
'root' => [
|
||||||
|
{ type: :image, image: { url: 'U1' }},
|
||||||
|
{ type: :video, video: { html: 'H1' }}
|
||||||
|
]
|
||||||
|
}, @mail_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_including_objects_serialization_using_serializable_hash
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
body: 'Body 1',
|
||||||
|
'attachment_ids' => @mail.attachments.map do |c|
|
||||||
|
{ id: c.object_id, type: model_name(c) }
|
||||||
|
end
|
||||||
|
}, @mail_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_including_objects_serialization_using_as_json
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'mail' => {
|
||||||
|
body: 'Body 1',
|
||||||
|
'attachment_ids' => @mail.attachments.map do |c|
|
||||||
|
{ id: c.object_id, type: model_name(c) }
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
'attachments' => [
|
||||||
|
{ type: :image, image: { url: 'U1' }},
|
||||||
|
{ type: :video, video: { html: 'H1' }}
|
||||||
|
]
|
||||||
|
}, @mail_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_nothing_including_objects_serialization_using_as_json
|
||||||
|
@association.embed = nil
|
||||||
|
@association.embed_in_root = true
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'mail' => { body: 'Body 1' },
|
||||||
|
'attachments' => [
|
||||||
|
{ type: :image, image: { url: 'U1' }},
|
||||||
|
{ type: :video, video: { html: 'H1' }}
|
||||||
|
]
|
||||||
|
}, @mail_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_using_a_given_serializer
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
@association.serializer_from_options = Class.new(ActiveModel::Serializer) do
|
||||||
|
def fake
|
||||||
|
'fake'
|
||||||
|
end
|
||||||
|
|
||||||
|
attributes :fake
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'mail' => {
|
||||||
|
body: 'Body 1',
|
||||||
|
'attachment_ids' => @mail.attachments.map do |c|
|
||||||
|
{ id: c.object_id, type: model_name(c) }
|
||||||
|
end
|
||||||
|
},
|
||||||
|
'attachments' => [
|
||||||
|
{ type: :image, image: { fake: 'fake' }},
|
||||||
|
{ type: :video, video: { fake: 'fake' }}
|
||||||
|
]
|
||||||
|
}, @mail_serializer.as_json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
265
test/unit/active_model/serializer/has_many_test.rb
Normal file
265
test/unit/active_model/serializer/has_many_test.rb
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class HasManyTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@association = PostSerializer._associations[:comments]
|
||||||
|
@old_association = @association.dup
|
||||||
|
|
||||||
|
@post = Post.new({ title: 'Title 1', body: 'Body 1', date: '1/1/2000' })
|
||||||
|
@post_serializer = PostSerializer.new(@post)
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
PostSerializer._associations[:comments] = @old_association
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_definition
|
||||||
|
assert_equal 1, PostSerializer._associations.length
|
||||||
|
assert_kind_of Association::HasMany, @association
|
||||||
|
assert_equal 'comments', @association.name
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_inheritance
|
||||||
|
inherited_serializer_klass = Class.new(PostSerializer) do
|
||||||
|
has_many :some_associations
|
||||||
|
end
|
||||||
|
another_inherited_serializer_klass = Class.new(PostSerializer)
|
||||||
|
|
||||||
|
assert_equal(PostSerializer._associations.length + 1,
|
||||||
|
inherited_serializer_klass._associations.length)
|
||||||
|
assert_equal(PostSerializer._associations.length,
|
||||||
|
another_inherited_serializer_klass._associations.length)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_serialization_using_serializable_hash
|
||||||
|
@association.embed = :ids
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id }
|
||||||
|
}, @post_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_serialization_using_as_json
|
||||||
|
@association.embed = :ids
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'post' => { title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id } }
|
||||||
|
}, @post_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_serialization_using_serializable_hash_and_key_from_options
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.key = 'key'
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
title: 'Title 1', body: 'Body 1', 'key' => @post.comments.map { |c| c.object_id }
|
||||||
|
}, @post_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_objects_serialization_using_serializable_hash
|
||||||
|
@association.embed = :objects
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
title: 'Title 1', body: 'Body 1', comments: [{ content: 'C1' }, { content: 'C2' }]
|
||||||
|
}, @post_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_objects_serialization_using_as_json
|
||||||
|
@association.embed = :objects
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'post' => { title: 'Title 1', body: 'Body 1', comments: [{ content: 'C1' }, { content: 'C2' }] }
|
||||||
|
}, @post_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_nil_objects_serialization_using_as_json
|
||||||
|
@association.embed = :objects
|
||||||
|
@post.instance_eval do
|
||||||
|
def comments
|
||||||
|
[nil]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'post' => { title: 'Title 1', body: 'Body 1', comments: [nil] }
|
||||||
|
}, @post_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_objects_serialization_using_serializable_hash_and_root_from_options
|
||||||
|
@association.embed = :objects
|
||||||
|
@association.embedded_key = 'root'
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
title: 'Title 1', body: 'Body 1', 'root' => [{ content: 'C1' }, { content: 'C2' }]
|
||||||
|
}, @post_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_including_objects_serialization_using_serializable_hash
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id }
|
||||||
|
}, @post_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_including_objects_serialization_using_as_json
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'post' => { title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id } },
|
||||||
|
'comments' => [{ content: 'C1' }, { content: 'C2' }]
|
||||||
|
}, @post_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_including_objects_serialization_when_invoked_from_parent_serializer
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
|
||||||
|
category = Category.new(name: 'Name 1')
|
||||||
|
category.instance_variable_set(:@posts, [@post])
|
||||||
|
category_serializer = CategorySerializer.new(category)
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'category' => {
|
||||||
|
name: 'Name 1',
|
||||||
|
posts: [{ title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id } }]
|
||||||
|
},
|
||||||
|
"comments" => [{ content: 'C1' }, { content: 'C2' }]
|
||||||
|
}, category_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_nothing_including_objects_serialization_using_as_json
|
||||||
|
@association.embed = nil
|
||||||
|
@association.embed_in_root = true
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'post' => { title: 'Title 1', body: 'Body 1' },
|
||||||
|
'comments' => [{ content: 'C1' }, { content: 'C2' }]
|
||||||
|
}, @post_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_using_a_given_serializer
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
@association.serializer_from_options = Class.new(Serializer) do
|
||||||
|
def content
|
||||||
|
object.read_attribute_for_serialization(:content) + '!'
|
||||||
|
end
|
||||||
|
|
||||||
|
attributes :content
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'post' => { title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id } },
|
||||||
|
'comments' => [{ content: 'C1!' }, { content: 'C2!' }]
|
||||||
|
}, @post_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_using_a_given_array_serializer
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
@association.serializer_from_options = Class.new(ArraySerializer) do
|
||||||
|
def serializable_object
|
||||||
|
{ my_content: ['fake'] }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'post' => { title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id } },
|
||||||
|
'comments' => { my_content: ['fake'] }
|
||||||
|
}, @post_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_objects_using_a_given_array_serializer
|
||||||
|
@association.serializer_from_options = Class.new(ArraySerializer) do
|
||||||
|
def serializable_object(options={})
|
||||||
|
{ my_content: ['fake'] }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'post' => { title: 'Title 1', body: 'Body 1', comments: { my_content: ['fake'] } }
|
||||||
|
}, @post_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_including_objects_serialization_with_embed_in_root_key
|
||||||
|
@association.embed_in_root = true
|
||||||
|
@association.embed_in_root_key = :linked
|
||||||
|
@association.embed = :ids
|
||||||
|
assert_equal({
|
||||||
|
'post' => {
|
||||||
|
title: 'Title 1', body: 'Body 1',
|
||||||
|
'comment_ids' => @post.comments.map(&:object_id)
|
||||||
|
},
|
||||||
|
linked: {
|
||||||
|
'comments' => [
|
||||||
|
{ content: 'C1' },
|
||||||
|
{ content: 'C2' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}, @post_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_using_embed_namespace_including_object_serialization_with_embed_in_root_key
|
||||||
|
@association.embed_in_root = true
|
||||||
|
@association.embed_in_root_key = :linked
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_namespace = :links
|
||||||
|
@association.key = :comments
|
||||||
|
assert_equal({
|
||||||
|
'post' => {
|
||||||
|
title: 'Title 1', body: 'Body 1',
|
||||||
|
links: {
|
||||||
|
comments: @post.comments.map(&:object_id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
linked: {
|
||||||
|
'comments' => [
|
||||||
|
{ content: 'C1' },
|
||||||
|
{ content: 'C2' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}, @post_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_objects_using_embed_namespace
|
||||||
|
@association.embed = :objects
|
||||||
|
@association.embed_namespace = :links
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'post' => {
|
||||||
|
title: 'Title 1', body: 'Body 1',
|
||||||
|
links: {
|
||||||
|
comments: [
|
||||||
|
{ content: 'C1' },
|
||||||
|
{ content: 'C2' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, @post_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_name_key_embedding_ids_serialization_using_serializable_hash
|
||||||
|
@association = NameKeyPostSerializer._associations[:comments]
|
||||||
|
@association.embed = :ids
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
title: 'Title 1', body: 'Body 1', 'comments' => @post.comments.map { |c| c.object_id }
|
||||||
|
}, NameKeyPostSerializer.new(@post).serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_name_key_embedding_ids_serialization_using_as_json
|
||||||
|
@association = NameKeyPostSerializer._associations[:comments]
|
||||||
|
@association.embed = :ids
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'name_key_post' => { title: 'Title 1', body: 'Body 1', 'comments' => @post.comments.map { |c| c.object_id } }
|
||||||
|
}, NameKeyPostSerializer.new(@post).as_json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class HasOneAndHasManyTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@post = SpecialPost.new({ title: 'T1', body: 'B1'})
|
||||||
|
@post_serializer = SpecialPostSerializer.new(@post)
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_side_load_has_one_and_has_many_in_same_array
|
||||||
|
assert_equal({
|
||||||
|
"post" => {
|
||||||
|
title: 'T1',
|
||||||
|
body: 'B1',
|
||||||
|
'comment_ids' => @post.comments.map { |c| c.object_id },
|
||||||
|
'special_comment_id' => @post_serializer.special_comment.object_id,
|
||||||
|
},
|
||||||
|
"comments" => [{ content: 'C1' }, { content: 'C2' }, { content: 'special' }]
|
||||||
|
}, @post_serializer.as_json(root: 'post'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
196
test/unit/active_model/serializer/has_one_polymorphic_test.rb
Normal file
196
test/unit/active_model/serializer/has_one_polymorphic_test.rb
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class HasOnePolymorphicTest < ActiveModel::TestCase
|
||||||
|
def setup
|
||||||
|
@association = InterviewSerializer._associations[:attachment]
|
||||||
|
@old_association = @association.dup
|
||||||
|
|
||||||
|
@interview = Interview.new({ text: 'Text 1' })
|
||||||
|
@interview_serializer = InterviewSerializer.new(@interview)
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
InterviewSerializer._associations[:attachment] = @old_association
|
||||||
|
end
|
||||||
|
|
||||||
|
def model_name(object)
|
||||||
|
object.class.to_s.demodulize.underscore.to_sym
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_definition
|
||||||
|
assert_equal 1, InterviewSerializer._associations.length
|
||||||
|
assert_kind_of Association::HasOne, @association
|
||||||
|
assert_equal true, @association.polymorphic
|
||||||
|
assert_equal 'attachment', @association.name
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_serialization_using_serializable_hash
|
||||||
|
@association.embed = :ids
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
text: 'Text 1',
|
||||||
|
'attachment_id' => {
|
||||||
|
type: model_name(@interview.attachment),
|
||||||
|
id: @interview.attachment.object_id
|
||||||
|
}
|
||||||
|
}, @interview_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_serialization_using_as_json
|
||||||
|
@association.embed = :ids
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'interview' => {
|
||||||
|
text: 'Text 1',
|
||||||
|
'attachment_id' => {
|
||||||
|
type: model_name(@interview.attachment),
|
||||||
|
id: @interview.attachment.object_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, @interview_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_serialization_using_serializable_hash_and_key_from_options
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.key = 'key'
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
text: 'Text 1',
|
||||||
|
'key' => {
|
||||||
|
type: model_name(@interview.attachment),
|
||||||
|
id: @interview.attachment.object_id
|
||||||
|
}
|
||||||
|
}, @interview_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_objects_serialization_using_serializable_hash
|
||||||
|
@association.embed = :objects
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
text: 'Text 1',
|
||||||
|
attachment: {
|
||||||
|
type: model_name(@interview.attachment),
|
||||||
|
model_name(@interview.attachment) => { url: 'U1'}
|
||||||
|
}
|
||||||
|
}, @interview_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_objects_serialization_using_as_json
|
||||||
|
@association.embed = :objects
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'interview' => {
|
||||||
|
text: 'Text 1',
|
||||||
|
attachment: {
|
||||||
|
type: model_name(@interview.attachment),
|
||||||
|
model_name(@interview.attachment) => { url: 'U1'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, @interview_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_nil_ids_serialization_using_as_json
|
||||||
|
@association.embed = :ids
|
||||||
|
@interview.instance_eval do
|
||||||
|
def attachment
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'interview' => { text: 'Text 1', 'attachment_id' => nil }
|
||||||
|
}, @interview_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_nil_objects_serialization_using_as_json
|
||||||
|
@association.embed = :objects
|
||||||
|
@interview.instance_eval do
|
||||||
|
def attachment
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'interview' => { text: 'Text 1', attachment: nil }
|
||||||
|
}, @interview_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_objects_serialization_using_serializable_hash_and_root_from_options
|
||||||
|
@association.embed = :objects
|
||||||
|
@association.embedded_key = 'root'
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
text: 'Text 1',
|
||||||
|
'root' => {
|
||||||
|
type: model_name(@interview.attachment),
|
||||||
|
model_name(@interview.attachment) => { url: 'U1'}
|
||||||
|
}
|
||||||
|
}, @interview_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_including_objects_serialization_using_serializable_hash
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
text: 'Text 1',
|
||||||
|
'attachment_id' => {
|
||||||
|
type: model_name(@interview.attachment),
|
||||||
|
id: @interview.attachment.object_id
|
||||||
|
}
|
||||||
|
}, @interview_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_including_objects_serialization_using_as_json
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'interview' => {
|
||||||
|
text: 'Text 1',
|
||||||
|
'attachment_id' => {
|
||||||
|
type: model_name(@interview.attachment),
|
||||||
|
id: @interview.attachment.object_id
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"attachments" => [{
|
||||||
|
type: model_name(@interview.attachment),
|
||||||
|
model_name(@interview.attachment) => {
|
||||||
|
url: 'U1'
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}, @interview_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_using_a_given_serializer
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
@association.serializer_from_options = Class.new(ActiveModel::Serializer) do
|
||||||
|
def name
|
||||||
|
'fake'
|
||||||
|
end
|
||||||
|
|
||||||
|
attributes :name
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'interview' => {
|
||||||
|
text: 'Text 1',
|
||||||
|
'attachment_id' => {
|
||||||
|
type: model_name(@interview.attachment),
|
||||||
|
id: @interview.attachment.object_id
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"attachments" => [{
|
||||||
|
type: model_name(@interview.attachment),
|
||||||
|
model_name(@interview.attachment) => {
|
||||||
|
name: 'fake'
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}, @interview_serializer.as_json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
253
test/unit/active_model/serializer/has_one_test.rb
Normal file
253
test/unit/active_model/serializer/has_one_test.rb
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class HasOneTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@association = UserSerializer._associations[:profile]
|
||||||
|
@old_association = @association.dup
|
||||||
|
|
||||||
|
@user = User.new({ name: 'Name 1', email: 'mail@server.com', gender: 'M' })
|
||||||
|
@user_serializer = UserSerializer.new(@user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
UserSerializer._associations[:profile] = @old_association
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_definition
|
||||||
|
assert_equal 1, UserSerializer._associations.length
|
||||||
|
assert_kind_of Association::HasOne, @association
|
||||||
|
assert_equal 'profile', @association.name
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_serialization_using_serializable_hash
|
||||||
|
@association.embed = :ids
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
name: 'Name 1', email: 'mail@server.com', 'profile_id' => @user.profile.object_id
|
||||||
|
}, @user_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_serialization_using_as_json
|
||||||
|
@association.embed = :ids
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'user' => { name: 'Name 1', email: 'mail@server.com', 'profile_id' => @user.profile.object_id }
|
||||||
|
}, @user_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_serialization_using_serializable_hash_and_key_from_options
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.key = 'key'
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
name: 'Name 1', email: 'mail@server.com', 'key' => @user.profile.object_id
|
||||||
|
}, @user_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_objects_serialization_using_serializable_hash
|
||||||
|
@association.embed = :objects
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
name: 'Name 1', email: 'mail@server.com', profile: { name: 'N1', description: 'D1' }
|
||||||
|
}, @user_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_objects_serialization_using_as_json
|
||||||
|
@association.embed = :objects
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'user' => { name: 'Name 1', email: 'mail@server.com', profile: { name: 'N1', description: 'D1' } }
|
||||||
|
}, @user_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_nil_ids_serialization_using_as_json
|
||||||
|
@association.embed = :ids
|
||||||
|
@user.instance_eval do
|
||||||
|
def profile
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'user' => { name: 'Name 1', email: 'mail@server.com', 'profile_id' => nil }
|
||||||
|
}, @user_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_nil_objects_serialization_using_as_json
|
||||||
|
@association.embed = :objects
|
||||||
|
@user.instance_eval do
|
||||||
|
def profile
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'user' => { name: 'Name 1', email: 'mail@server.com', profile: nil }
|
||||||
|
}, @user_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_objects_serialization_using_serializable_hash_and_root_from_options
|
||||||
|
@association.embed = :objects
|
||||||
|
@association.embedded_key = 'root'
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
name: 'Name 1', email: 'mail@server.com', 'root' => { name: 'N1', description: 'D1' }
|
||||||
|
}, @user_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_including_objects_serialization_using_serializable_hash
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
name: 'Name 1', email: 'mail@server.com', 'profile_id' => @user.profile.object_id
|
||||||
|
}, @user_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_nil_ids_including_objects_serialization_using_as_json
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
@user.instance_eval do
|
||||||
|
def profile
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'user' => { name: 'Name 1', email: 'mail@server.com', 'profile_id' => nil },
|
||||||
|
'profiles' => []
|
||||||
|
}, @user_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_including_objects_serialization_using_as_json
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'user' => { name: 'Name 1', email: 'mail@server.com', 'profile_id' => @user.profile.object_id },
|
||||||
|
'profiles' => [{ name: 'N1', description: 'D1' }]
|
||||||
|
}, @user_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_including_objects_serialization_when_invoked_from_parent_serializer
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
|
||||||
|
user_info = UserInfo.new
|
||||||
|
user_info.instance_variable_set(:@user, @user)
|
||||||
|
user_info_serializer = UserInfoSerializer.new(user_info)
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'user_info' => { user: { name: 'Name 1', email: 'mail@server.com', 'profile_id' => @user.profile.object_id } },
|
||||||
|
'profiles' => [{ name: 'N1', description: 'D1' }]
|
||||||
|
}, user_info_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_using_a_given_serializer
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.embed_in_root = true
|
||||||
|
@association.serializer_from_options = Class.new(Serializer) do
|
||||||
|
def name
|
||||||
|
'fake'
|
||||||
|
end
|
||||||
|
|
||||||
|
attributes :name
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'user' => { name: 'Name 1', email: 'mail@server.com', 'profile_id' => @user.profile.object_id },
|
||||||
|
'profiles' => [{ name: 'fake' }]
|
||||||
|
}, @user_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_objects_using_a_given_serializer
|
||||||
|
@association.serializer_from_options = Class.new(Serializer) do
|
||||||
|
def name
|
||||||
|
'fake'
|
||||||
|
end
|
||||||
|
|
||||||
|
attributes :name
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'user' => { name: 'Name 1', email: 'mail@server.com', profile: { name: 'fake' } }
|
||||||
|
}, @user_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_objects_with_nil_values
|
||||||
|
user_info = UserInfo.new
|
||||||
|
user_info.instance_eval do
|
||||||
|
def user
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
user_info_serializer = UserInfoSerializer.new(user_info)
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'user_info' => { user: nil }
|
||||||
|
}, user_info_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_using_embed_namespace
|
||||||
|
@association.embed_namespace = :links
|
||||||
|
@association.embed = :ids
|
||||||
|
@association.key = :profile
|
||||||
|
assert_equal({
|
||||||
|
'user' => {
|
||||||
|
name: 'Name 1', email: 'mail@server.com',
|
||||||
|
links: {
|
||||||
|
profile: @user.profile.object_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, @user_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_asociations_embedding_objects_using_embed_namespace
|
||||||
|
@association.embed_namespace = :links
|
||||||
|
@association.embed = :objects
|
||||||
|
assert_equal({
|
||||||
|
'user' => {
|
||||||
|
name: 'Name 1', email: 'mail@server.com',
|
||||||
|
links: {
|
||||||
|
profile: { name: 'N1', description: 'D1' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, @user_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_embedding_ids_using_embed_namespace_and_embed_in_root_key
|
||||||
|
@association.embed_in_root = true
|
||||||
|
@association.embed_in_root_key = :linked
|
||||||
|
@association.embed = :ids
|
||||||
|
assert_equal({
|
||||||
|
'user' => {
|
||||||
|
name: 'Name 1', email: 'mail@server.com', 'profile_id' => @user.profile.object_id
|
||||||
|
},
|
||||||
|
linked: {
|
||||||
|
'profiles' => [ { name: 'N1', description: 'D1' } ]
|
||||||
|
}
|
||||||
|
}, @user_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_name_key_embedding_ids_serialization_using_serializable_hash
|
||||||
|
@association = NameKeyUserSerializer._associations[:profile]
|
||||||
|
@association.embed = :ids
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
name: 'Name 1', email: 'mail@server.com', 'profile' => @user.profile.object_id
|
||||||
|
}, NameKeyUserSerializer.new(@user).serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_associations_name_key_embedding_ids_serialization_using_as_json
|
||||||
|
@association = NameKeyUserSerializer._associations[:profile]
|
||||||
|
@association.embed = :ids
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'name_key_user' => { name: 'Name 1', email: 'mail@server.com', 'profile' => @user.profile.object_id }
|
||||||
|
}, NameKeyUserSerializer.new(@user).as_json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
25
test/unit/active_model/serializer/key_format_test.rb
Normal file
25
test/unit/active_model/serializer/key_format_test.rb
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class KeyFormatTest < Minitest::Test
|
||||||
|
def test_lower_camel_format_option
|
||||||
|
object = WebLog.new({ name: 'Name 1', display_name: 'Display Name 1'})
|
||||||
|
serializer = WebLogSerializer.new(object, key_format: :lower_camel)
|
||||||
|
|
||||||
|
expected = { name: 'Name 1', displayName: 'Display Name 1' }
|
||||||
|
|
||||||
|
assert_equal expected, serializer.serializable_object
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_lower_camel_format_serializer
|
||||||
|
object = WebLog.new({ name: 'Name 1', display_name: 'Display Name 1'})
|
||||||
|
serializer = WebLogLowerCamelSerializer.new(object)
|
||||||
|
|
||||||
|
expected = { name: 'Name 1', displayName: 'Display Name 1' }
|
||||||
|
|
||||||
|
assert_equal expected, serializer.serializable_object
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
39
test/unit/active_model/serializer/meta_test.rb
Normal file
39
test/unit/active_model/serializer/meta_test.rb
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class MetaTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_meta
|
||||||
|
profile_serializer = ProfileSerializer.new(@profile, root: 'profile', meta: { total: 10 })
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'profile' => {
|
||||||
|
name: 'Name 1',
|
||||||
|
description: 'Description 1'
|
||||||
|
},
|
||||||
|
meta: {
|
||||||
|
total: 10
|
||||||
|
}
|
||||||
|
}, profile_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_meta_using_meta_key
|
||||||
|
profile_serializer = ProfileSerializer.new(@profile, root: 'profile', meta_key: :my_meta, my_meta: { total: 10 })
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'profile' => {
|
||||||
|
name: 'Name 1',
|
||||||
|
description: 'Description 1'
|
||||||
|
},
|
||||||
|
my_meta: {
|
||||||
|
total: 10
|
||||||
|
}
|
||||||
|
}, profile_serializer.as_json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
42
test/unit/active_model/serializer/options_test.rb
Normal file
42
test/unit/active_model/serializer/options_test.rb
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class OptionsTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@serializer = ProfileSerializer.new(nil, context: {foo: :bar})
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_custom_options_are_accessible_from_serializer
|
||||||
|
assert_equal({foo: :bar}, @serializer.context)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class SerializationOptionsTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||||
|
@profile_serializer = ProfileSerializer.new(@profile)
|
||||||
|
@profile_serializer.instance_eval do
|
||||||
|
def description
|
||||||
|
serialization_options[:force_the_description]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@category = Category.new({name: 'Category 1'})
|
||||||
|
@category_serializer = CategorySerializer.new(@category)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_filtered_attributes_serialization
|
||||||
|
forced_description = "This is a test"
|
||||||
|
assert_equal({
|
||||||
|
'profile' => { name: 'Name 1', description: forced_description }
|
||||||
|
}, @profile_serializer.as_json(force_the_description: forced_description))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_filtered_attributes_serialization_across_association
|
||||||
|
assert_equal("'T1'",
|
||||||
|
@category_serializer.as_json(highlight_keyword: 'T1')['category'][:posts][0][:title])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
117
test/unit/active_model/serializer/root_test.rb
Normal file
117
test/unit/active_model/serializer/root_test.rb
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class RootAsOptionTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@old_root = ProfileSerializer._root
|
||||||
|
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||||
|
@serializer = ProfileSerializer.new(@profile, root: :initialize)
|
||||||
|
ProfileSerializer._root = true
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
ProfileSerializer._root = @old_root
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_root_is_not_displayed_using_serializable_hash
|
||||||
|
assert_equal({
|
||||||
|
name: 'Name 1', description: 'Description 1'
|
||||||
|
}, @serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_root_using_as_json
|
||||||
|
assert_equal({
|
||||||
|
initialize: {
|
||||||
|
name: 'Name 1', description: 'Description 1'
|
||||||
|
}
|
||||||
|
}, @serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_root_from_serializer_name
|
||||||
|
@serializer = ProfileSerializer.new(@profile)
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
'profile' => {
|
||||||
|
name: 'Name 1', description: 'Description 1'
|
||||||
|
}
|
||||||
|
}, @serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_root_as_argument_takes_precedence
|
||||||
|
assert_equal({
|
||||||
|
argument: {
|
||||||
|
name: 'Name 1', description: 'Description 1'
|
||||||
|
}
|
||||||
|
}, @serializer.as_json(root: :argument))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_using_false_root_in_initializer_takes_precedence
|
||||||
|
ProfileSerializer._root = 'root'
|
||||||
|
@serializer = ProfileSerializer.new(@profile, root: false)
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
name: 'Name 1', description: 'Description 1'
|
||||||
|
}, @serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_root_inheritance
|
||||||
|
ProfileSerializer._root = 'profile'
|
||||||
|
|
||||||
|
inherited_serializer_klass = Class.new(ProfileSerializer)
|
||||||
|
inherited_serializer_klass._root = 'inherited_profile'
|
||||||
|
|
||||||
|
another_inherited_serializer_klass = Class.new(ProfileSerializer)
|
||||||
|
|
||||||
|
assert_equal('inherited_profile',
|
||||||
|
inherited_serializer_klass._root)
|
||||||
|
assert_equal('profile',
|
||||||
|
another_inherited_serializer_klass._root)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class RootInSerializerTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@old_root = ProfileSerializer._root
|
||||||
|
ProfileSerializer._root = :in_serializer
|
||||||
|
profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||||
|
@serializer = ProfileSerializer.new(profile)
|
||||||
|
@rooted_serializer = ProfileSerializer.new(profile, root: :initialize)
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
ProfileSerializer._root = @old_root
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_root_is_not_displayed_using_serializable_hash
|
||||||
|
assert_equal({
|
||||||
|
name: 'Name 1', description: 'Description 1'
|
||||||
|
}, @serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_root_using_as_json
|
||||||
|
assert_equal({
|
||||||
|
in_serializer: {
|
||||||
|
name: 'Name 1', description: 'Description 1'
|
||||||
|
}
|
||||||
|
}, @serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_root_in_initializer_takes_precedence
|
||||||
|
assert_equal({
|
||||||
|
initialize: {
|
||||||
|
name: 'Name 1', description: 'Description 1'
|
||||||
|
}
|
||||||
|
}, @rooted_serializer.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_root_as_argument_takes_precedence
|
||||||
|
assert_equal({
|
||||||
|
argument: {
|
||||||
|
name: 'Name 1', description: 'Description 1'
|
||||||
|
}
|
||||||
|
}, @rooted_serializer.as_json(root: :argument))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
49
test/unit/active_model/serializer/scope_test.rb
Normal file
49
test/unit/active_model/serializer/scope_test.rb
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class ScopeTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@serializer = ProfileSerializer.new(nil, scope: current_user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_scope
|
||||||
|
assert_equal('user', @serializer.scope)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def current_user
|
||||||
|
'user'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class NestedScopeTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@association = UserSerializer._associations[:profile]
|
||||||
|
@old_association = @association.dup
|
||||||
|
@user = User.new({ name: 'Name 1', email: 'mail@server.com', gender: 'M' })
|
||||||
|
@user_serializer = UserSerializer.new(@user, scope: 'user')
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
UserSerializer._associations[:profile] = @old_association
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_scope_passed_through
|
||||||
|
@association.serializer_from_options = Class.new(Serializer) do
|
||||||
|
def name
|
||||||
|
scope
|
||||||
|
end
|
||||||
|
|
||||||
|
attributes :name
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal({
|
||||||
|
name: 'Name 1', email: 'mail@server.com', profile: { name: 'user' }
|
||||||
|
}, @user_serializer.serializable_hash)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
35
test/unit/active_model/serializer/url_helpers_test.rb
Normal file
35
test/unit/active_model/serializer/url_helpers_test.rb
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
class UrlHelpersTest < Minitest::Test
|
||||||
|
include Rails.application.routes.url_helpers
|
||||||
|
|
||||||
|
def setup
|
||||||
|
Object.const_set 'UserController', Class.new(ActionController::Base) do
|
||||||
|
def show
|
||||||
|
render text: 'profile'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Rails.application.routes.draw do
|
||||||
|
get '/profile/:id', as: :profile, controller: :user, action: :show
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_url_helpers_are_available
|
||||||
|
serializer = Class.new(ActiveModel::Serializer) do
|
||||||
|
attributes :url
|
||||||
|
|
||||||
|
def url
|
||||||
|
profile_url(id: object.object_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
profile = Profile.new
|
||||||
|
|
||||||
|
assert_equal({ url: profile_url(id: profile.object_id) },
|
||||||
|
serializer.new(profile).as_json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
50
test/unit/active_model/serilizable_test.rb
Normal file
50
test/unit/active_model/serilizable_test.rb
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class SerializableTest
|
||||||
|
class InstrumentationTest < Minitest::Test
|
||||||
|
def setup
|
||||||
|
@events = []
|
||||||
|
|
||||||
|
@subscriber = ActiveSupport::Notifications.subscribe('!serialize.active_model_serializers') do |name, start, finish, id, payload|
|
||||||
|
@events << { name: name, serializer: payload[:serializer] }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
ActiveSupport::Notifications.unsubscribe(@subscriber) if defined?(@subscriber)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_instruments_default_serializer
|
||||||
|
DefaultSerializer.new(1).as_json
|
||||||
|
|
||||||
|
assert_equal [{ name: '!serialize.active_model_serializers', serializer: 'ActiveModel::DefaultSerializer' }], @events
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_instruments_serializer
|
||||||
|
profile = Profile.new(name: 'Name 1', description: 'Description 1', comments: 'Comments 1')
|
||||||
|
serializer = ProfileSerializer.new(profile)
|
||||||
|
|
||||||
|
serializer.as_json
|
||||||
|
|
||||||
|
assert_equal [{ name: '!serialize.active_model_serializers', serializer: 'ProfileSerializer' }], @events
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_instruments_array_serializer
|
||||||
|
profiles = [
|
||||||
|
Profile.new(name: 'Name 1', description: 'Description 1', comments: 'Comments 1'),
|
||||||
|
Profile.new(name: 'Name 2', description: 'Description 2', comments: 'Comments 2')
|
||||||
|
]
|
||||||
|
serializer = ArraySerializer.new(profiles)
|
||||||
|
|
||||||
|
serializer.as_json
|
||||||
|
|
||||||
|
assert_equal [
|
||||||
|
{ name: '!serialize.active_model_serializers', serializer: 'ProfileSerializer' },
|
||||||
|
{ name: '!serialize.active_model_serializers', serializer: 'ProfileSerializer' },
|
||||||
|
{ name: '!serialize.active_model_serializers', serializer: 'ActiveModel::ArraySerializer' }
|
||||||
|
], @events
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in New Issue
Block a user