mirror of
https://github.com/ditkrg/active_model_serializers.git
synced 2026-01-22 22:06:50 +00:00
Compare commits
No commits in common. "v0.8.4" and "master" have entirely different histories.
29
.github/ISSUE_TEMPLATE.md
vendored
Normal file
29
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
#### 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
Normal file
15
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
#### Purpose
|
||||
|
||||
|
||||
#### Changes
|
||||
|
||||
|
||||
#### Caveats
|
||||
|
||||
|
||||
#### Related GitHub issues
|
||||
|
||||
|
||||
#### Additional helpful information
|
||||
|
||||
|
||||
17
.gitignore
vendored
17
.gitignore
vendored
@ -4,15 +4,32 @@
|
||||
.config
|
||||
.yardoc
|
||||
Gemfile.lock
|
||||
Gemfile.local
|
||||
InstalledFiles
|
||||
_yardoc
|
||||
coverage
|
||||
doc/
|
||||
lib/bundler/man
|
||||
pkg
|
||||
Vagrantfile
|
||||
.vagrant
|
||||
rdoc
|
||||
spec/reports
|
||||
test/tmp
|
||||
test/version_tmp
|
||||
tmp
|
||||
*.swp
|
||||
.ruby-version
|
||||
.ruby-gemset
|
||||
vendor/bundle
|
||||
tags
|
||||
|
||||
# silly macs
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
Icon?
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
32
.travis.yml
32
.travis.yml
@ -1,34 +1,10 @@
|
||||
language: ruby
|
||||
|
||||
sudo: false
|
||||
rvm:
|
||||
# - 1.8.7
|
||||
# - ree
|
||||
# - jruby-18mode
|
||||
# - 1.9.2
|
||||
# - 1.9.3
|
||||
- jruby-19mode
|
||||
- 2.0.0
|
||||
- 2.1
|
||||
- 2.2
|
||||
- rbx-2
|
||||
install: bundle install --path=vendor/bundle --retry=3 --jobs=3
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- vendor/bundle
|
||||
|
||||
script:
|
||||
- bundle exec rake ci
|
||||
env:
|
||||
# - "RAILS_VERSION=3.0"
|
||||
# - "RAILS_VERSION=3.1"
|
||||
# - "RAILS_VERSION=3.2"
|
||||
- "RAILS_VERSION=4.0"
|
||||
- "RAILS_VERSION=4.1"
|
||||
- "RAILS_VERSION=4.2"
|
||||
# - "RAILS_VERSION=master"
|
||||
matrix:
|
||||
exclude:
|
||||
# - rvm: 1.8.7
|
||||
# - ree
|
||||
# - jruby-18mode
|
||||
# - rvm: 1.9.2
|
||||
fast_finish: true
|
||||
- true
|
||||
|
||||
92
CHANGELOG-0-08.md
Normal file
92
CHANGELOG-0-08.md
Normal file
@ -0,0 +1,92 @@
|
||||
## 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).
|
||||
74
CHANGELOG-0-09.md
Normal file
74
CHANGELOG-0-09.md
Normal file
@ -0,0 +1,74 @@
|
||||
## 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)
|
||||
466
CHANGELOG-0-10.md
Normal file
466
CHANGELOG-0-10.md
Normal file
@ -0,0 +1,466 @@
|
||||
## 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).
|
||||
15
CHANGELOG-prehistory.md
Normal file
15
CHANGELOG-prehistory.md
Normal file
@ -0,0 +1,15 @@
|
||||
## 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)
|
||||
103
CHANGELOG.md
103
CHANGELOG.md
@ -1,102 +1,19 @@
|
||||
# UNRELEASED
|
||||
## Dev
|
||||
|
||||
### v0.8.4 (2017-09-19)
|
||||
### [master (unreleased)](https://github.com/rails-api/active_model_serializers/compare/master..dev)
|
||||
|
||||
- [#1675](https://github.com/rails-api/active_model_serializers/pull/1675) Fix memory leak with :scope_name.
|
||||
Supplying :scope_name causes `ActiveModel::Serializer#initialize` to
|
||||
define a method on the class, which retains a reference to the
|
||||
serializer instance. (@Botje)
|
||||
- [#1276](https://github.com/rails-api/active_model_serializers/pull/1276) Fix serializers were never including associations on cache hits (@kieran)
|
||||
- [#1503](https://github.com/rails-api/active_model_serializers/pull/1503) Add documentation with example to `README` for POROs and alternative ORMs (@feministy)
|
||||
- [#1376](https://github.com/rails-api/active_model_serializers/pull/1376) Test against Rails >= 4.0, Ruby >= 1.9.3 and remove Ruby 1.8 and 1.9.2 support (@bf4, @mhuggins)
|
||||
Breaking changes:
|
||||
|
||||
### v0.8.3 (2014-12-10)
|
||||
- [#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)
|
||||
Features:
|
||||
|
||||
### 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)
|
||||
Fixes:
|
||||
|
||||
### 0.8.1 (May 6, 2013)
|
||||
Misc:
|
||||
|
||||
* Fix bug whereby a serializer using 'options' would blow up.
|
||||
## [0.10.x](CHANGELOG-0-10.md)
|
||||
|
||||
### 0.8.0 (May 5, 2013)
|
||||
## [0.09.x](CHANGELOG-0-09.md)
|
||||
|
||||
* Attributes can now have optional types.
|
||||
## [0.08.x](CHANGELOG-0-08.md)
|
||||
|
||||
* 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).
|
||||
## [Prehistory](CHANGELOG-prehistory.md)
|
||||
|
||||
74
CODE_OF_CONDUCT.md
Normal file
74
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,74 @@
|
||||
# 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/
|
||||
100
CONTRIBUTING.md
Normal file
100
CONTRIBUTING.md
Normal file
@ -0,0 +1,100 @@
|
||||
## Have an issue?
|
||||
|
||||
Before opening an issue, try the following:
|
||||
|
||||
##### Consult the documentation
|
||||
|
||||
See if your issue can be resolved by information in the [documentation](README.md).
|
||||
|
||||
##### Check for an existing issue
|
||||
|
||||
Take a look at the issues to see if a similar one has already been created. If
|
||||
one exists, please add any additional information that might expedite
|
||||
resolution.
|
||||
|
||||
#### Open an issue
|
||||
|
||||
If the documentation wasn't able to help resolve the issue and no issue already
|
||||
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
586
DESIGN.textile
@ -1,586 +0,0 @@
|
||||
<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.
|
||||
38
Gemfile
38
Gemfile
@ -1,38 +0,0 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
# Specify gem dependencies in active_model_serializers.gemspec
|
||||
gemspec
|
||||
|
||||
version = ENV['RAILS_VERSION'] || '4.0'
|
||||
|
||||
if version == 'master'
|
||||
gem 'rack', github: 'rack/rack'
|
||||
gem 'arel', github: 'rails/arel'
|
||||
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
|
||||
else
|
||||
gem_version = "~> #{version}.0"
|
||||
gem 'railties', gem_version
|
||||
gem 'activesupport', gem_version
|
||||
gem 'activemodel', gem_version
|
||||
gem 'actionpack', gem_version
|
||||
gem 'activerecord', gem_version, group: :test
|
||||
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
|
||||
gem 'tzinfo-data', platforms: (@windows_platforms + [:jruby])
|
||||
|
||||
# JRuby versions before 9.x report their version as "1.9.x" or lower, so lock these to an older version of mime-types
|
||||
if defined?(JRUBY_VERSION) and Gem::ruby_version < Gem::Version.new("2.0.0")
|
||||
gem 'mime-types', '< 3'
|
||||
end
|
||||
@ -1,4 +1,6 @@
|
||||
Copyright (c) 2011-2012 José Valim & Yehuda Katz
|
||||
Copyright (c) 2014 Steve Klabnik
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
@ -18,4 +20,3 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
719
README.md
719
README.md
@ -1,672 +1,111 @@
|
||||
[](https://travis-ci.org/rails-api/active_model_serializers) [](https://codeclimate.com/github/rails-api/active_model_serializers)
|
||||
# ActiveModelSerializers
|
||||
|
||||
# Purpose
|
||||
## About
|
||||
|
||||
The purpose of `ActiveModel::Serializers` is to provide an object to
|
||||
encapsulate serialization of `ActiveModel` objects, including `ActiveRecord`
|
||||
objects.
|
||||
ActiveModelSerializers is undergoing some renovations. See [Development Status](#status-of-ams).
|
||||
|
||||
Serializers know about both a model and the `current_user`, so you can
|
||||
customize serialization based upon whether a user is authorized to see the
|
||||
content.
|
||||
## Getting Help
|
||||
|
||||
In short, **serializers replace hash-driven development with object-oriented
|
||||
development.**
|
||||
If you find a bug, please report an [Issue](https://github.com/rails-api/active_model_serializers/issues/new)
|
||||
and see our [contributing guide](CONTRIBUTING.md).
|
||||
|
||||
# Installing Serializers
|
||||
If you have a question, please [post to Stack Overflow](http://stackoverflow.com/questions/tagged/active-model-serializers).
|
||||
|
||||
The easiest way to install `ActiveModel::Serializers` is to add it to your
|
||||
`Gemfile`:
|
||||
If you'd like to chat, we have a [community slack](http://amserializers.herokuapp.com).
|
||||
|
||||
```ruby
|
||||
gem "active_model_serializers", "~> 0.8.0"
|
||||
```
|
||||
Thanks!
|
||||
|
||||
Then, install it on the command line:
|
||||
## Documentation
|
||||
|
||||
```
|
||||
$ bundle install
|
||||
```
|
||||
If you're reading this at https://github.com/rails-api/active_model_serializers you are
|
||||
reading documentation for our `master`, which is not yet released.
|
||||
|
||||
# Creating a Serializer
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<a href='https://github.com/rails-api/active_model_serializers/tree/0-10-stable'>0.10 (0-10-stable) Documentation
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href='http://www.rubydoc.info/gems/active_model_serializers/0.10.6'>
|
||||
<img src='http://img.shields.io/badge/yard-docs-blue.svg' />
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href='https://github.com/rails-api/active_model_serializers/tree/v0.10.6/docs'>
|
||||
Guides
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a href='https://github.com/rails-api/active_model_serializers/tree/0-9-stable'>0.9 (0-9-stable) Documentation
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href='http://www.rubydoc.info/github/rails-api/active_model_serializers/0-9-stable'>
|
||||
<img src='http://img.shields.io/badge/yard-docs-blue.svg' />
|
||||
</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a href='https://github.com/rails-api/active_model_serializers/tree/0-8-stable'>0.8 (0-8-stable) Documentation
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href='http://www.rubydoc.info/github/rails-api/active_model_serializers/0-8-stable'>
|
||||
<img src='http://img.shields.io/badge/yard-docs-blue.svg' />
|
||||
</a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
The easiest way to create a new serializer is to generate a new resource, which
|
||||
will generate a serializer at the same time:
|
||||
|
||||
```
|
||||
$ rails g resource post title:string body:string
|
||||
```
|
||||
## Status of AMS
|
||||
|
||||
This will generate a serializer in `app/serializers/post_serializer.rb` for
|
||||
your new model. You can also generate a serializer for an existing model with
|
||||
the serializer generator:
|
||||
### *Status*:
|
||||
|
||||
```
|
||||
$ rails g serializer post
|
||||
```
|
||||
- ❗️ All existing PRs against master will need to be closed and re-opened against 0-10-stable, if so desired
|
||||
- ❗️ Master, for the moment, won't have any released version of AMS on it.
|
||||
- :eyes: See below for [alternatives](#alternatives)
|
||||
|
||||
### Support for POROs and other ORMs.
|
||||
|
||||
Currently `ActiveModel::Serializers` adds serialization support to all models
|
||||
that descend from `ActiveRecord` or include `Mongoid::Document`. If you are:
|
||||
### *Changes to 0.10.x maintenance*:
|
||||
|
||||
- using another ORM, or
|
||||
- using objects that are `ActiveModel` compliant but do not descend from
|
||||
`ActiveRecord` *or* include `Mongoid::Document`
|
||||
- The 0.10.x version has become a huge maintenance version. We had hoped to get it in shape for a 1.0 release, but it is clear that isn't going to happen. Almost none of the maintainers from 0.8, 0.9, or earlier 0.10 are still working on AMS. We'll continue to maintain 0.10.x on the 0-10-stable branch, but maintainers won't otherwise be actively developing on it.
|
||||
- We may choose to make a 0.11.x ( 0-11-stable) release based on 0-10-stable that just removes the deprecations.
|
||||
|
||||
You must add an include statement for `ActiveModel::SerializerSupport` to
|
||||
make models serializable.
|
||||
### *What's happening to AMS*:
|
||||
|
||||
If you also want to make collections serializable, you should include
|
||||
`ActiveModel::ArraySerializerSupport` into your ORM's
|
||||
relation/criteria class.
|
||||
- There's been a lot of churn around AMS since it began back in [Rails 3.2](CHANGELOG-prehistory.md) and a lot of new libraries are around and the JSON:API spec has reached 1.0.
|
||||
- If there is to be a 1.0 release of AMS, it will need to address the general needs of serialization in much the way ActiveJob can be used with different workers.
|
||||
- The next major release *is* in development. We're starting simple and avoiding, at least at the outset, all the complications in AMS version, especially all the implicit behavior from guessing the serializer, to the association's serializer, to the serialization type, etc.
|
||||
- The basic idea is that models to serializers are a one to many relationship. Everything will need to be explicit. If you want to serialize a User with a UserSerializer, you'll need to call it directly. The serializer will essentially be for defining a basic JSON:API resource object: id, type, attributes, and relationships. The serializer will have an as_json method and can be told which fields (attributes/relationships) to serialize to JSON and will likely *not* know serialize any more than the relations id and type. Serializing anything more about the relations would require code that called a serializer. (This is still somewhat in discussion).
|
||||
- If this works out, the idea is to get something into Rails that existing libraries can use.
|
||||
|
||||
Example model (`app/models/avatar.rb`):
|
||||
See [PR 2121](https://github.com/rails-api/active_model_serializers/pull/2121) where these changes were introduced for more information and any discussion.
|
||||
|
||||
```ruby
|
||||
class Avatar
|
||||
include ActiveModel::SerializerSupport
|
||||
# etc, etc
|
||||
end
|
||||
```
|
||||
|
||||
If your classes follow the naming conventions prescribed by `ActiveModel`,
|
||||
you don't need to do anything different in your controller to render the
|
||||
serialized json.
|
||||
|
||||
# ActiveModel::Serializer
|
||||
## Alternatives
|
||||
|
||||
All new serializers descend from ActiveModel::Serializer
|
||||
- [jsonapi-rb](http://jsonapi-rb.org/) is a [highly performant](https://gist.github.com/NullVoxPopuli/748e89ddc1732b42fdf42435d773734a) and modular JSON:API-only implementation. There's a vibrant community around it that has produced projects such as [JSON:API Suite](https://jsonapi-suite.github.io/jsonapi_suite/).
|
||||
- [fast_jsonapi](https://github.com/fast-jsonapi/fast_jsonapi) is a lightning fast JSON:API serializer for Ruby Objects.
|
||||
- [jsonapi-resources](https://github.com/cerebris/jsonapi-resources) is a popular resource-focused framework for implementing JSON:API servers.
|
||||
- [blueprinter](https://github.com/procore/blueprinter) is a fast, declarative, and API spec agnostic serializer that uses composable views to reduce duplication. From your friends at Procore.
|
||||
|
||||
# render :json
|
||||
|
||||
In your controllers, when you use `render :json`, Rails will now first search
|
||||
for a serializer for the object and use it if available.
|
||||
For benchmarks against alternatives, see https://github.com/rails-api/active_model_serializers/tree/benchmarks
|
||||
|
||||
```ruby
|
||||
class PostsController < ApplicationController
|
||||
def show
|
||||
@post = Post.find(params[:id])
|
||||
render :json => @post
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
In this case, Rails will look for a serializer named `PostSerializer`, and if
|
||||
it exists, use it to serialize the `Post`.
|
||||
|
||||
This also works with `respond_with`, which uses `to_json` under the hood. Also
|
||||
note that any options passed to `render :json` will be passed to your
|
||||
serializer and available as `@options` inside.
|
||||
## Semantic Versioning
|
||||
|
||||
To specify a custom serializer for an object, there are 2 options:
|
||||
This project adheres to [semver](http://semver.org/)
|
||||
|
||||
#### 1. Specify the serializer in your model:
|
||||
## Contributing
|
||||
|
||||
```ruby
|
||||
class Post < ActiveRecord::Base
|
||||
def active_model_serializer
|
||||
FancyPostSerializer
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
#### 2. Specify the serializer when you render the object:
|
||||
|
||||
```ruby
|
||||
render :json => @post, :serializer => FancyPostSerializer
|
||||
```
|
||||
|
||||
## Arrays
|
||||
|
||||
In your controllers, when you use `render :json` for an array of objects, AMS will
|
||||
use `ActiveModel::ArraySerializer` (included in this project) as the base serializer,
|
||||
and the individual `Serializer` for the objects contained in that array.
|
||||
|
||||
```ruby
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
attributes :title, :body
|
||||
end
|
||||
|
||||
class PostsController < ApplicationController
|
||||
def index
|
||||
@posts = Post.all
|
||||
render :json => @posts
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
Given the example above, the index action will return
|
||||
|
||||
```json
|
||||
{
|
||||
"posts":
|
||||
[
|
||||
{ "title": "Post 1", "body": "Hello!" },
|
||||
{ "title": "Post 2", "body": "Goodbye!" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
By default, the root element is the name of the controller. For example, `PostsController`
|
||||
generates a root element "posts". To change it:
|
||||
|
||||
```ruby
|
||||
render :json => @posts, :root => "some_posts"
|
||||
```
|
||||
|
||||
You may disable the root element for arrays at the top level, which will result in
|
||||
more concise json. See the next section for ways on how to do this. Disabling the
|
||||
root element of the array with any of those methods will produce
|
||||
|
||||
```json
|
||||
[
|
||||
{ "title": "Post 1", "body": "Hello!" },
|
||||
{ "title": "Post 2", "body": "Goodbye!" }
|
||||
]
|
||||
```
|
||||
|
||||
To specify a custom serializer for the items within an array:
|
||||
|
||||
```ruby
|
||||
render :json => @posts, :each_serializer => FancyPostSerializer
|
||||
```
|
||||
|
||||
## Disabling the root element
|
||||
|
||||
You have 4 options to disable the root element, each with a slightly different scope:
|
||||
|
||||
#### 1. Disable root globally for all, or per class
|
||||
|
||||
In an initializer:
|
||||
|
||||
```ruby
|
||||
ActiveSupport.on_load(:active_model_serializers) do
|
||||
# Disable for all serializers (except ArraySerializer)
|
||||
ActiveModel::Serializer.root = false
|
||||
|
||||
# Disable for ArraySerializer
|
||||
ActiveModel::ArraySerializer.root = false
|
||||
end
|
||||
```
|
||||
|
||||
#### 2. Disable root per render call in your controller
|
||||
|
||||
```ruby
|
||||
render :json => @posts, :root => false
|
||||
```
|
||||
|
||||
#### 3. Subclass the serializer, and specify using it
|
||||
|
||||
```ruby
|
||||
class CustomArraySerializer < ActiveModel::ArraySerializer
|
||||
self.root = false
|
||||
end
|
||||
|
||||
# controller:
|
||||
render :json => @posts, :serializer => CustomArraySerializer
|
||||
```
|
||||
|
||||
#### 4. Define default_serializer_options in your controller
|
||||
|
||||
If you define `default_serializer_options` method in your controller,
|
||||
all serializers in actions of this controller and it's children will use them.
|
||||
One of the options may be `root: false`
|
||||
|
||||
```ruby
|
||||
def default_serializer_options
|
||||
{
|
||||
root: false
|
||||
}
|
||||
end
|
||||
```
|
||||
|
||||
## Getting the old version
|
||||
|
||||
If you find that your project is already relying on the old rails to_json
|
||||
change `render :json` to `render :json => @your_object.to_json`.
|
||||
|
||||
# Attributes and Associations
|
||||
|
||||
Once you have a serializer, you can specify which attributes and associations
|
||||
you would like to include in the serialized form.
|
||||
|
||||
```ruby
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
attributes :id, :title, :body
|
||||
has_many :comments
|
||||
end
|
||||
```
|
||||
|
||||
## Attributes
|
||||
|
||||
For specified attributes, a serializer will look up the attribute on the
|
||||
object you passed to `render :json`. It uses
|
||||
`read_attribute_for_serialization`, which `ActiveRecord` objects implement as a
|
||||
regular attribute lookup.
|
||||
|
||||
Before looking up the attribute on the object, a serializer will check for the
|
||||
presence of a method with the name of the attribute. This allows serializers to
|
||||
include properties beyond the simple attributes of the model. For example:
|
||||
|
||||
```ruby
|
||||
class PersonSerializer < ActiveModel::Serializer
|
||||
attributes :first_name, :last_name, :full_name
|
||||
|
||||
def full_name
|
||||
"#{object.first_name} #{object.last_name}"
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
Within a serializer's methods, you can access the object being
|
||||
serialized as `object`.
|
||||
|
||||
You can also access the `current_user` method, which provides an
|
||||
authorization context to your serializer. By default, the context
|
||||
is the current user of your application, but this
|
||||
[can be customized](#customizing-scope).
|
||||
|
||||
Serializers will check for the presence of a method named
|
||||
`include_[ATTRIBUTE]?` to determine whether a particular attribute should be
|
||||
included in the output. This is typically used to customize output
|
||||
based on `current_user`. For example:
|
||||
|
||||
```ruby
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
attributes :id, :title, :body, :author
|
||||
|
||||
def include_author?
|
||||
current_user.admin?
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
The type of a computed attribute (like :full_name above) is not easily
|
||||
calculated without some sophisticated static code analysis. To specify the
|
||||
type of a computed attribute:
|
||||
|
||||
```ruby
|
||||
class PersonSerializer < ActiveModel::Serializer
|
||||
attributes :first_name, :last_name, {:full_name => :string}
|
||||
|
||||
def full_name
|
||||
"#{object.first_name} #{object.last_name}"
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
If you would like the key in the outputted JSON to be different from its name
|
||||
in ActiveRecord, you can use the `:key` option to customize it:
|
||||
|
||||
```ruby
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
attributes :id, :body
|
||||
|
||||
# look up :subject on the model, but use +title+ in the JSON
|
||||
attribute :subject, :key => :title
|
||||
has_many :comments
|
||||
end
|
||||
```
|
||||
|
||||
If you would like to add meta information to the outputted JSON, use the `:meta`
|
||||
option:
|
||||
|
||||
```ruby
|
||||
render :json => @posts, :serializer => CustomArraySerializer, :meta => {:total => 10}
|
||||
```
|
||||
|
||||
The above usage of `:meta` will produce the following:
|
||||
|
||||
```json
|
||||
{
|
||||
"meta": { "total": 10 },
|
||||
"posts": [
|
||||
{ "title": "Post 1", "body": "Hello!" },
|
||||
{ "title": "Post 2", "body": "Goodbye!" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
If you would like to change the meta key name you can use the `:meta_key` option:
|
||||
|
||||
```ruby
|
||||
render :json => @posts, :serializer => CustomArraySerializer, :meta => {:total => 10}, :meta_key => 'meta_object'
|
||||
```
|
||||
|
||||
The above usage of `:meta_key` will produce the following:
|
||||
|
||||
```json
|
||||
{
|
||||
"meta_object": { "total": 10 },
|
||||
"posts": [
|
||||
{ "title": "Post 1", "body": "Hello!" },
|
||||
{ "title": "Post 2", "body": "Goodbye!" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
If you would like direct, low-level control of attribute serialization, you can
|
||||
completely override the `attributes` method to return the hash you need:
|
||||
|
||||
```ruby
|
||||
class PersonSerializer < ActiveModel::Serializer
|
||||
attributes :first_name, :last_name
|
||||
|
||||
def attributes
|
||||
hash = super
|
||||
if current_user.admin?
|
||||
hash["ssn"] = object.ssn
|
||||
hash["secret"] = object.mothers_maiden_name
|
||||
end
|
||||
hash
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
## Associations
|
||||
|
||||
For specified associations, the serializer will look up the association and
|
||||
then serialize each element of the association. For instance, a `has_many
|
||||
:comments` association will create a new `CommentSerializer` for each comment
|
||||
and use it to serialize the comment.
|
||||
|
||||
By default, serializers simply look up the association on the original object.
|
||||
You can customize this behavior by implementing a method with the name of the
|
||||
association and returning a different Array. Often, you will do this to
|
||||
customize the objects returned based on the current user.
|
||||
|
||||
```ruby
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
attributes :id, :title, :body
|
||||
has_many :comments
|
||||
|
||||
# only let the user see comments he created.
|
||||
def comments
|
||||
object.comments.where(:created_by => current_user)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
As with attributes, you can change the JSON key that the serializer should
|
||||
use for a particular association.
|
||||
|
||||
```ruby
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
attributes :id, :title, :body
|
||||
|
||||
# look up comments, but use +my_comments+ as the key in JSON
|
||||
has_many :comments, :key => :my_comments
|
||||
end
|
||||
```
|
||||
|
||||
Also, as with attributes, serializers will check for the presence
|
||||
of a method named `include_[ASSOCIATION]?` to determine whether a particular association
|
||||
should be included in the output. For example:
|
||||
|
||||
```ruby
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
attributes :id, :title, :body
|
||||
has_many :comments
|
||||
|
||||
def include_comments?
|
||||
!object.comments_disabled?
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
If you would like lower-level control of association serialization, you can
|
||||
override `include_associations!` to specify which associations should be included:
|
||||
|
||||
```ruby
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
attributes :id, :title, :body
|
||||
has_one :author
|
||||
has_many :comments
|
||||
|
||||
def include_associations!
|
||||
include! :author if current_user.admin?
|
||||
include! :comments unless object.comments_disabled?
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
You may also use the `:serializer` option to specify a custom serializer class and the `:polymorphic` option to specify an association that is polymorphic (STI), e.g.:
|
||||
|
||||
```ruby
|
||||
has_many :comments, :serializer => CommentShortSerializer
|
||||
has_one :reviewer, :polymorphic => true
|
||||
```
|
||||
|
||||
Serializers are only concerned with multiplicity, and not ownership. `belongs_to` ActiveRecord associations can be included using `has_one` in your serializer.
|
||||
|
||||
## Embedding Associations
|
||||
|
||||
By default, associations will be embedded inside the serialized object. So if
|
||||
you have a post, the outputted JSON will look like:
|
||||
|
||||
```json
|
||||
{
|
||||
"post": {
|
||||
"id": 1,
|
||||
"title": "New post",
|
||||
"body": "A body!",
|
||||
"comments": [
|
||||
{ "id": 1, "body": "what a dumb post" }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This is convenient for simple use-cases, but for more complex clients, it is
|
||||
better to supply an Array of IDs for the association. This makes your API more
|
||||
flexible from a performance standpoint and avoids wasteful duplication.
|
||||
|
||||
To embed IDs instead of associations, simply use the `embed` class method:
|
||||
|
||||
```ruby
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
embed :ids
|
||||
|
||||
attributes :id, :title, :body
|
||||
has_many :comments
|
||||
end
|
||||
```
|
||||
|
||||
Now, any associations will be supplied as an Array of IDs:
|
||||
|
||||
```json
|
||||
{
|
||||
"post": {
|
||||
"id": 1,
|
||||
"title": "New post",
|
||||
"body": "A body!",
|
||||
"comment_ids": [ 1, 2, 3 ]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, you can choose to embed only the ids or the associated objects per association:
|
||||
|
||||
```ruby
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
attributes :id, :title, :body
|
||||
|
||||
has_many :comments, embed: :objects
|
||||
has_many :tags, embed: :ids
|
||||
end
|
||||
```
|
||||
|
||||
The JSON will look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"post": {
|
||||
"id": 1,
|
||||
"title": "New post",
|
||||
"body": "A body!",
|
||||
"comments": [
|
||||
{ "id": 1, "body": "what a dumb post" }
|
||||
],
|
||||
"tag_ids": [ 1, 2, 3 ]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In addition to supplying an Array of IDs, you may want to side-load the data
|
||||
alongside the main object. This makes it easier to process the entire package
|
||||
of data without having to recursively scan the tree looking for embedded
|
||||
information. It also ensures that associations that are shared between several
|
||||
objects (like tags), are only delivered once for the entire payload.
|
||||
|
||||
You can specify that the data be included like this:
|
||||
|
||||
```ruby
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
embed :ids, :include => true
|
||||
|
||||
attributes :id, :title, :body
|
||||
has_many :comments
|
||||
end
|
||||
```
|
||||
|
||||
Assuming that the comments also `has_many :tags`, you will get a JSON like
|
||||
this:
|
||||
|
||||
```json
|
||||
{
|
||||
"post": {
|
||||
"id": 1,
|
||||
"title": "New post",
|
||||
"body": "A body!",
|
||||
"comment_ids": [ 1, 2 ]
|
||||
},
|
||||
"comments": [
|
||||
{ "id": 1, "body": "what a dumb post", "tag_ids": [ 1, 2 ] },
|
||||
{ "id": 2, "body": "i liked it", "tag_ids": [ 1, 3 ] },
|
||||
],
|
||||
"tags": [
|
||||
{ "id": 1, "name": "short" },
|
||||
{ "id": 2, "name": "whiny" },
|
||||
{ "id": 3, "name": "happy" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
You can also specify a different root for the embedded objects than the key
|
||||
used to reference them:
|
||||
|
||||
```ruby
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
embed :ids, :include => true
|
||||
|
||||
attributes :id, :title, :body
|
||||
has_many :comments, :key => :comment_ids, :root => :comment_objects
|
||||
end
|
||||
```
|
||||
|
||||
This would generate JSON that would look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"post": {
|
||||
"id": 1,
|
||||
"title": "New post",
|
||||
"body": "A body!",
|
||||
"comment_ids": [ 1 ]
|
||||
},
|
||||
"comment_objects": [
|
||||
{ "id": 1, "body": "what a dumb post" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
You can also specify a different attribute to use rather than the ID of the
|
||||
objects:
|
||||
|
||||
```ruby
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
embed :ids, :include => true
|
||||
|
||||
attributes :id, :title, :body
|
||||
has_many :comments, :embed_key => :external_id
|
||||
end
|
||||
```
|
||||
|
||||
This would generate JSON that would look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"post": {
|
||||
"id": 1,
|
||||
"title": "New post",
|
||||
"body": "A body!",
|
||||
"comment_ids": [ "COMM001" ]
|
||||
},
|
||||
"comments": [
|
||||
{ "id": 1, "external_id": "COMM001", "body": "what a dumb post" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**NOTE**: The `embed :ids` mechanism is primary useful for clients that process
|
||||
data in bulk and load it into a local store. For these clients, the ability to
|
||||
easily see all of the data per type, rather than having to recursively scan the
|
||||
data looking for information, is extremely useful.
|
||||
|
||||
If you are mostly working with the data in simple scenarios and manually making
|
||||
Ajax requests, you probably just want to use the default embedded behavior.
|
||||
|
||||
## Customizing Scope
|
||||
|
||||
In a serializer, `current_user` is the current authorization scope which the controller
|
||||
provides to the serializer when you call `render :json`. By default, this is
|
||||
`current_user`, but can be customized in your controller by calling
|
||||
`serialization_scope`:
|
||||
|
||||
```ruby
|
||||
class ApplicationController < ActionController::Base
|
||||
serialization_scope :current_admin
|
||||
end
|
||||
```
|
||||
|
||||
The above example will also change the scope name from `current_user` to
|
||||
`current_admin`.
|
||||
|
||||
Please note that, until now, `serialization_scope` doesn't accept a second
|
||||
object with options for specifying which actions should or should not take a
|
||||
given scope in consideration.
|
||||
|
||||
To be clear, it's not possible, yet, to do something like this:
|
||||
|
||||
```ruby
|
||||
class SomeController < ApplicationController
|
||||
serialization_scope :current_admin, :except => [:index, :show]
|
||||
end
|
||||
```
|
||||
|
||||
So, in order to have a fine grained control of what each action should take in
|
||||
consideration for its scope, you may use something like this:
|
||||
|
||||
```ruby
|
||||
class CitiesController < ApplicationController
|
||||
serialization_scope nil
|
||||
|
||||
def index
|
||||
@cities = City.all
|
||||
|
||||
render :json => @cities, :each_serializer => CitySerializer
|
||||
end
|
||||
|
||||
def show
|
||||
@city = City.find(params[:id])
|
||||
|
||||
render :json => @city, :scope => current_admin, :scope_name => :current_admin
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
Assuming that the `current_admin` method needs to make a query in the database
|
||||
for the current user, the advantage of this approach is that, by setting
|
||||
`serialization_scope` to `nil`, the `index` action no longer will need to make
|
||||
that query, only the `show` action will.
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||
|
||||
25
Rakefile
25
Rakefile
@ -1,22 +1,5 @@
|
||||
#!/usr/bin/env rake
|
||||
require "bundler/gem_tasks"
|
||||
require "rake/testtask"
|
||||
|
||||
desc 'Run tests'
|
||||
Rake::TestTask.new(:test) do |t|
|
||||
t.libs << 'lib'
|
||||
t.libs << 'test'
|
||||
t.pattern = 'test/**/*_test.rb'
|
||||
t.ruby_opts = ['-r./test/test_helper.rb']
|
||||
t.verbose = true
|
||||
begin
|
||||
require 'bundler/setup'
|
||||
rescue LoadError
|
||||
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
||||
end
|
||||
|
||||
desc 'Benchmark'
|
||||
task :bench do
|
||||
load 'bench/perf.rb'
|
||||
end
|
||||
|
||||
task :default => :test
|
||||
|
||||
desc 'CI test task'
|
||||
task :ci => :default
|
||||
|
||||
@ -1,24 +1,20 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# coding: utf-8
|
||||
|
||||
$:.unshift File.expand_path("../lib", __FILE__)
|
||||
require "active_model/serializers/version"
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = 'active_model_serializers'
|
||||
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'
|
||||
|
||||
Gem::Specification.new do |gem|
|
||||
gem.authors = ["José Valim", "Yehuda Katz"]
|
||||
gem.email = ["jose.valim@gmail.com", "wycats@gmail.com"]
|
||||
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"
|
||||
spec.files = `git ls-files -z`.split("\x0")
|
||||
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
||||
spec.require_paths = ['lib']
|
||||
spec.executables = []
|
||||
|
||||
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
||||
gem.files = `git ls-files`.split("\n")
|
||||
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
||||
gem.name = "active_model_serializers"
|
||||
gem.require_paths = ["lib"]
|
||||
gem.version = ActiveModel::Serializer::VERSION
|
||||
|
||||
gem.add_dependency 'activemodel', '>= 3.0'
|
||||
gem.add_development_dependency "rails", ">= 3.0"
|
||||
gem.add_development_dependency "pry"
|
||||
gem.add_development_dependency "minitest"
|
||||
spec.required_ruby_version = '>= 2.1'
|
||||
end
|
||||
|
||||
20
appveyor.yml
20
appveyor.yml
@ -1,27 +1,11 @@
|
||||
version: '{build}'
|
||||
version: 1.0.{build}-{branch}
|
||||
|
||||
skip_tags: true
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- ruby_version: "200"
|
||||
- ruby_version: "200-x64"
|
||||
- ruby_version: "21"
|
||||
- ruby_version: "21-x64"
|
||||
|
||||
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 ci
|
||||
- true
|
||||
|
||||
build: off
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
require "active_model_serializers"
|
||||
require "active_support/json"
|
||||
require "benchmark"
|
||||
|
||||
class User < Struct.new(:id,:name,:age,:about)
|
||||
include ActiveModel::SerializerSupport
|
||||
|
||||
def fast_hash
|
||||
h = {
|
||||
id: read_attribute_for_serialization(:id),
|
||||
name: read_attribute_for_serialization(:name),
|
||||
about: read_attribute_for_serialization(:about)
|
||||
}
|
||||
h[:age] = read_attribute_for_serialization(:age) if age > 18
|
||||
h
|
||||
end
|
||||
end
|
||||
|
||||
class UserSerializer < ActiveModel::Serializer
|
||||
attributes :id, :name, :age, :about
|
||||
|
||||
def include_age?
|
||||
object.age > 18
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
u = User.new(1, "sam", 10, "about")
|
||||
s = UserSerializer.new(u)
|
||||
|
||||
n = 100000
|
||||
|
||||
Benchmark.bmbm {|x|
|
||||
x.report("init") { n.times { UserSerializer.new(u) } }
|
||||
x.report("fast_hash") { n.times { u.fast_hash } }
|
||||
x.report("attributes") { n.times { UserSerializer.new(u).attributes } }
|
||||
x.report("serializable_hash") { n.times { UserSerializer.new(u).serializable_hash } }
|
||||
}
|
||||
|
||||
|
||||
19
cruft.md
19
cruft.md
@ -1,19 +0,0 @@
|
||||
As of Ruby 1.9.3, it is impossible to dynamically generate a Symbol
|
||||
through interpolation without generating garbage. Theoretically, Ruby
|
||||
should be able to take care of this by building up the String in C and
|
||||
interning the C String.
|
||||
|
||||
Because of this, we avoid generating dynamic Symbols at runtime. For
|
||||
example, instead of generating the instrumentation event dynamically, we
|
||||
have a constant with a Hash of events:
|
||||
|
||||
```ruby
|
||||
INSTRUMENT = {
|
||||
:serialize => :"serialize.serializer",
|
||||
:associations => :"associations.serializer"
|
||||
}
|
||||
```
|
||||
|
||||
If Ruby ever fixes this issue and avoids generating garbage with dynamic
|
||||
symbols, this code can be removed.
|
||||
|
||||
15
docs/rfcs/template.md
Normal file
15
docs/rfcs/template.md
Normal file
@ -0,0 +1,15 @@
|
||||
- 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
|
||||
@ -1,61 +0,0 @@
|
||||
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
|
||||
|
||||
included do
|
||||
class_attribute :_serialization_scope
|
||||
self._serialization_scope = :current_user
|
||||
end
|
||||
|
||||
def serialization_scope
|
||||
send(_serialization_scope) if _serialization_scope &&
|
||||
respond_to?(_serialization_scope, true)
|
||||
end
|
||||
|
||||
def default_serializer_options
|
||||
end
|
||||
|
||||
[:_render_option_json, :_render_with_renderer_json].each do |renderer_method|
|
||||
define_method renderer_method do |resource, options|
|
||||
json = ActiveModel::Serializer.build_json(self, resource, options)
|
||||
|
||||
if json
|
||||
super(json, options)
|
||||
else
|
||||
super(resource, options)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def serialization_scope(scope)
|
||||
self._serialization_scope = scope
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,104 +0,0 @@
|
||||
require "active_support/core_ext/class/attribute"
|
||||
require 'active_support/dependencies'
|
||||
require 'active_support/descendants_tracker'
|
||||
|
||||
module ActiveModel
|
||||
# Active Model Array Serializer
|
||||
#
|
||||
# Serializes an Array, checking if each element implements
|
||||
# the +active_model_serializer+ method.
|
||||
#
|
||||
# To disable serialization of root elements:
|
||||
#
|
||||
# ActiveModel::ArraySerializer.root = false
|
||||
#
|
||||
class ArraySerializer
|
||||
extend ActiveSupport::DescendantsTracker
|
||||
|
||||
attr_reader :object, :options
|
||||
|
||||
class_attribute :root
|
||||
|
||||
class_attribute :cache
|
||||
class_attribute :perform_caching
|
||||
|
||||
class << self
|
||||
# set perform caching like root
|
||||
def cached(value = true)
|
||||
self.perform_caching = value
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(object, options={})
|
||||
@object, @options = object, options
|
||||
end
|
||||
|
||||
def meta_key
|
||||
@options[:meta_key].try(:to_sym) || :meta
|
||||
end
|
||||
|
||||
def include_meta(hash)
|
||||
hash[meta_key] = @options[:meta] if @options.has_key?(:meta)
|
||||
end
|
||||
|
||||
def as_json(*args)
|
||||
@options[:hash] = hash = {}
|
||||
@options[:unique_values] = {}
|
||||
|
||||
if root = @options[:root]
|
||||
hash.merge!(root => serializable_array)
|
||||
include_meta hash
|
||||
hash
|
||||
else
|
||||
serializable_array
|
||||
end
|
||||
end
|
||||
|
||||
def to_json(*args)
|
||||
if perform_caching?
|
||||
cache.fetch expand_cache_key([self.class.to_s.underscore, cache_key, 'to-json']) do
|
||||
super
|
||||
end
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def serializable_array
|
||||
if perform_caching?
|
||||
cache.fetch expand_cache_key([self.class.to_s.underscore, cache_key, 'serializable-array']) do
|
||||
_serializable_array
|
||||
end
|
||||
else
|
||||
_serializable_array
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def _serializable_array
|
||||
@object.map do |item|
|
||||
if @options.has_key? :each_serializer
|
||||
serializer = @options[:each_serializer]
|
||||
elsif item.respond_to?(:active_model_serializer)
|
||||
serializer = item.active_model_serializer
|
||||
end
|
||||
|
||||
serializable = serializer ? serializer.new(item, @options) : DefaultSerializer.new(item, @options.merge(:root => false))
|
||||
|
||||
if serializable.respond_to?(:serializable_hash)
|
||||
serializable.serializable_hash
|
||||
else
|
||||
serializable.as_json
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def expand_cache_key(*args)
|
||||
ActiveSupport::Cache.expand_cache_key(args)
|
||||
end
|
||||
|
||||
def perform_caching?
|
||||
perform_caching && cache && respond_to?(:cache_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,514 +0,0 @@
|
||||
require "active_support/core_ext/class/attribute"
|
||||
require "active_support/core_ext/module/anonymous"
|
||||
require 'active_support/dependencies'
|
||||
require 'active_support/descendants_tracker'
|
||||
|
||||
module ActiveModel
|
||||
# Active Model Serializer
|
||||
#
|
||||
# Provides a basic serializer implementation that allows you to easily
|
||||
# control how a given object is going to be serialized. On initialization,
|
||||
# it expects two objects as arguments, a resource and options. For example,
|
||||
# one may do in a controller:
|
||||
#
|
||||
# PostSerializer.new(@post, :scope => current_user).to_json
|
||||
#
|
||||
# The object to be serialized is the +@post+ and the current user is passed
|
||||
# in for authorization purposes.
|
||||
#
|
||||
# We use the scope to check if a given attribute should be serialized or not.
|
||||
# For example, some attributes may only be returned if +current_user+ is the
|
||||
# author of the post:
|
||||
#
|
||||
# class PostSerializer < ActiveModel::Serializer
|
||||
# attributes :title, :body
|
||||
# has_many :comments
|
||||
#
|
||||
# private
|
||||
#
|
||||
# def attributes
|
||||
# hash = super
|
||||
# hash.merge!(:email => post.email) if author?
|
||||
# hash
|
||||
# end
|
||||
#
|
||||
# def author?
|
||||
# post.author == scope
|
||||
# end
|
||||
# end
|
||||
#
|
||||
class Serializer
|
||||
extend ActiveSupport::DescendantsTracker
|
||||
|
||||
INCLUDE_METHODS = {}
|
||||
INSTRUMENT = { :serialize => :"serialize.serializer", :associations => :"associations.serializer" }
|
||||
|
||||
class IncludeError < StandardError
|
||||
attr_reader :source, :association
|
||||
|
||||
def initialize(source, association)
|
||||
@source, @association = source, association
|
||||
end
|
||||
|
||||
def to_s
|
||||
"Cannot serialize #{association} when #{source} does not have a root!"
|
||||
end
|
||||
end
|
||||
|
||||
class_attribute :_attributes
|
||||
self._attributes = {}
|
||||
|
||||
class_attribute :_associations
|
||||
self._associations = {}
|
||||
|
||||
class_attribute :_root
|
||||
class_attribute :_embed
|
||||
self._embed = :objects
|
||||
class_attribute :_root_embed
|
||||
|
||||
class_attribute :cache
|
||||
class_attribute :perform_caching
|
||||
|
||||
class << self
|
||||
# set perform caching like root
|
||||
def cached(value = true)
|
||||
self.perform_caching = value
|
||||
end
|
||||
|
||||
# Define attributes to be used in the serialization.
|
||||
def attributes(*attrs)
|
||||
|
||||
self._attributes = _attributes.dup
|
||||
|
||||
attrs.each do |attr|
|
||||
if Hash === attr
|
||||
attr.each {|attr_real, key| attribute attr_real, :key => key }
|
||||
else
|
||||
attribute attr
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def attribute(attr, options={})
|
||||
self._attributes = _attributes.merge(attr.is_a?(Hash) ? attr : {attr => options[:key] || attr.to_s.gsub(/\?$/, '').to_sym})
|
||||
|
||||
attr = attr.keys[0] if attr.is_a? Hash
|
||||
|
||||
unless method_defined?(attr)
|
||||
define_method attr do
|
||||
object.read_attribute_for_serialization(attr.to_sym)
|
||||
end
|
||||
end
|
||||
|
||||
define_include_method attr
|
||||
|
||||
# protect inheritance chains and open classes
|
||||
# if a serializer inherits from another OR
|
||||
# attributes are added later in a classes lifecycle
|
||||
# poison the cache
|
||||
define_method :_fast_attributes do
|
||||
raise NameError
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def associate(klass, attrs) #:nodoc:
|
||||
options = attrs.extract_options!
|
||||
self._associations = _associations.dup
|
||||
|
||||
attrs.each do |attr|
|
||||
unless method_defined?(attr)
|
||||
define_method attr do
|
||||
object.send attr
|
||||
end
|
||||
end
|
||||
|
||||
define_include_method attr
|
||||
|
||||
self._associations[attr] = klass.refine(attr, options)
|
||||
end
|
||||
end
|
||||
|
||||
def define_include_method(name)
|
||||
method = "include_#{name}?".to_sym
|
||||
|
||||
INCLUDE_METHODS[name] = method
|
||||
|
||||
unless method_defined?(method)
|
||||
define_method method do
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Defines an association in the object should be rendered.
|
||||
#
|
||||
# The serializer object should implement the association name
|
||||
# as a method which should return an array when invoked. If a method
|
||||
# with the association name does not exist, the association name is
|
||||
# dispatched to the serialized object.
|
||||
def has_many(*attrs)
|
||||
associate(Associations::HasMany, attrs)
|
||||
end
|
||||
|
||||
# Defines an association in the object should be rendered.
|
||||
#
|
||||
# The serializer object should implement the association name
|
||||
# as a method which should return an object when invoked. If a method
|
||||
# with the association name does not exist, the association name is
|
||||
# dispatched to the serialized object.
|
||||
def has_one(*attrs)
|
||||
associate(Associations::HasOne, attrs)
|
||||
end
|
||||
|
||||
# Return a schema hash for the current serializer. This information
|
||||
# can be used to generate clients for the serialized output.
|
||||
#
|
||||
# The schema hash has two keys: +attributes+ and +associations+.
|
||||
#
|
||||
# The +attributes+ hash looks like this:
|
||||
#
|
||||
# { :name => :string, :age => :integer }
|
||||
#
|
||||
# The +associations+ hash looks like this:
|
||||
# { :posts => { :has_many => :posts } }
|
||||
#
|
||||
# If :key is used:
|
||||
#
|
||||
# class PostsSerializer < ActiveModel::Serializer
|
||||
# has_many :posts, :key => :my_posts
|
||||
# end
|
||||
#
|
||||
# the hash looks like this:
|
||||
#
|
||||
# { :my_posts => { :has_many => :posts }
|
||||
#
|
||||
# This information is extracted from the serializer's model class,
|
||||
# which is provided by +SerializerClass.model_class+.
|
||||
#
|
||||
# The schema method uses the +columns_hash+ and +reflect_on_association+
|
||||
# methods, provided by default by ActiveRecord. You can implement these
|
||||
# methods on your custom models if you want the serializer's schema method
|
||||
# to work.
|
||||
#
|
||||
# TODO: This is currently coupled to Active Record. We need to
|
||||
# figure out a way to decouple those two.
|
||||
def schema
|
||||
klass = model_class
|
||||
columns = klass.columns_hash
|
||||
|
||||
attrs = {}
|
||||
_attributes.each do |name, key|
|
||||
if column = columns[name.to_s]
|
||||
attrs[key] = column.type
|
||||
else
|
||||
# Computed attribute (method on serializer or model). We cannot
|
||||
# infer the type, so we put nil, unless specified in the attribute declaration
|
||||
if name != key
|
||||
attrs[name] = key
|
||||
else
|
||||
attrs[key] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
associations = {}
|
||||
_associations.each do |attr, association_class|
|
||||
association = association_class.new(attr, self)
|
||||
|
||||
if model_association = klass.reflect_on_association(association.name)
|
||||
# Real association.
|
||||
associations[association.key] = { model_association.macro => model_association.name }
|
||||
else
|
||||
# Computed association. We could infer has_many vs. has_one from
|
||||
# the association class, but that would make it different from
|
||||
# real associations, which read has_one vs. belongs_to from the
|
||||
# model.
|
||||
associations[association.key] = nil
|
||||
end
|
||||
end
|
||||
|
||||
{ :attributes => attrs, :associations => associations }
|
||||
end
|
||||
|
||||
# The model class associated with this serializer.
|
||||
def model_class
|
||||
name.sub(/Serializer$/, '').constantize
|
||||
end
|
||||
|
||||
# Define how associations should be embedded.
|
||||
#
|
||||
# embed :objects # Embed associations as full objects
|
||||
# embed :ids # Embed only the association ids
|
||||
# embed :ids, :include => true # Embed the association ids and include objects in the root
|
||||
#
|
||||
def embed(type, options={})
|
||||
self._embed = type
|
||||
self._root_embed = true if options[:include]
|
||||
end
|
||||
|
||||
# Defines the root used on serialization. If false, disables the root.
|
||||
def root(name)
|
||||
self._root = name
|
||||
end
|
||||
alias_method :root=, :root
|
||||
|
||||
# Used internally to create a new serializer object based on controller
|
||||
# settings and options for a given resource. These settings are typically
|
||||
# set during the request lifecycle or by the controller class, and should
|
||||
# not be manually defined for this method.
|
||||
def build_json(controller, resource, options)
|
||||
default_options = controller.send(:default_serializer_options) || {}
|
||||
options = default_options.merge(options || {})
|
||||
|
||||
serializer = options.delete(:serializer) ||
|
||||
(resource.respond_to?(:active_model_serializer) &&
|
||||
resource.active_model_serializer)
|
||||
|
||||
return serializer unless serializer
|
||||
|
||||
if resource.respond_to?(:to_ary)
|
||||
unless serializer <= ActiveModel::ArraySerializer
|
||||
raise ArgumentError.new("#{serializer.name} is not an ArraySerializer. " +
|
||||
"You may want to use the :each_serializer option instead.")
|
||||
end
|
||||
|
||||
if options[:root] != false && serializer.root != false
|
||||
# the serializer for an Array is ActiveModel::ArraySerializer
|
||||
options[:root] ||= serializer.root || controller.controller_name
|
||||
end
|
||||
end
|
||||
|
||||
options[:scope] = controller.serialization_scope unless options.has_key?(:scope)
|
||||
options[:scope_name] = controller._serialization_scope
|
||||
options[:url_options] = controller.url_options
|
||||
|
||||
serializer.new(resource, options)
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :object, :options
|
||||
|
||||
def initialize(object, options={})
|
||||
@object, @options = object, options
|
||||
|
||||
scope_name = @options[:scope_name]
|
||||
if scope_name && !respond_to?(scope_name)
|
||||
self.singleton_class.send :alias_method, scope_name, :scope
|
||||
end
|
||||
end
|
||||
|
||||
def root_name
|
||||
return false if self._root == false
|
||||
|
||||
class_name = self.class.name.demodulize.underscore.sub(/_serializer$/, '').to_sym unless self.class.name.blank?
|
||||
|
||||
if self._root == true
|
||||
class_name
|
||||
else
|
||||
self._root || class_name
|
||||
end
|
||||
end
|
||||
|
||||
def url_options
|
||||
@options[:url_options] || {}
|
||||
end
|
||||
|
||||
def meta_key
|
||||
@options[:meta_key].try(:to_sym) || :meta
|
||||
end
|
||||
|
||||
def include_meta(hash)
|
||||
hash[meta_key] = @options[:meta] if @options.has_key?(:meta)
|
||||
end
|
||||
|
||||
def to_json(*args)
|
||||
if perform_caching?
|
||||
cache.fetch expand_cache_key([self.class.to_s.underscore, cache_key, 'to-json']) do
|
||||
super
|
||||
end
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a json representation of the serializable
|
||||
# object including the root.
|
||||
def as_json(options={})
|
||||
options ||= {}
|
||||
if root = options.fetch(:root, @options.fetch(:root, root_name))
|
||||
@options[:hash] = hash = {}
|
||||
@options[:unique_values] = {}
|
||||
|
||||
hash.merge!(root => serializable_hash)
|
||||
include_meta hash
|
||||
hash
|
||||
else
|
||||
serializable_hash
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a hash representation of the serializable
|
||||
# object without the root.
|
||||
def serializable_hash
|
||||
@node = if perform_caching?
|
||||
cache.fetch expand_cache_key([self.class.to_s.underscore, cache_key, 'serializable-hash']) do
|
||||
_serializable_hash
|
||||
end
|
||||
else
|
||||
_serializable_hash
|
||||
end
|
||||
|
||||
include_associations! if @object.present? && _embed
|
||||
@node
|
||||
end
|
||||
|
||||
def include_associations!
|
||||
_associations.each_key do |name|
|
||||
include!(name) if include?(name)
|
||||
end
|
||||
end
|
||||
|
||||
def include?(name)
|
||||
return false if @options.key?(:only) && !Array(@options[:only]).include?(name)
|
||||
return false if @options.key?(:except) && Array(@options[:except]).include?(name)
|
||||
send INCLUDE_METHODS[name]
|
||||
end
|
||||
|
||||
def include!(name, options={})
|
||||
# Make sure that if a special options[:hash] was passed in, we generate
|
||||
# a new unique values hash and don't clobber the original. If the hash
|
||||
# passed in is the same as the current options hash, use the current
|
||||
# unique values.
|
||||
#
|
||||
# TODO: Should passing in a Hash even be public API here?
|
||||
unique_values =
|
||||
if hash = options[:hash]
|
||||
if @options[:hash] == hash
|
||||
@options[:unique_values] ||= {}
|
||||
else
|
||||
{}
|
||||
end
|
||||
else
|
||||
hash = @options[:hash]
|
||||
@options[:unique_values] ||= {}
|
||||
end
|
||||
|
||||
node = options[:node] ||= @node
|
||||
value = options[:value]
|
||||
|
||||
if options[:include] == nil
|
||||
if @options.key?(:include)
|
||||
options[:include] = @options[:include].include?(name)
|
||||
elsif @options.include?(:exclude)
|
||||
options[:include] = !@options[:exclude].include?(name)
|
||||
end
|
||||
end
|
||||
|
||||
association_class =
|
||||
if klass = _associations[name]
|
||||
klass
|
||||
elsif value.respond_to?(:to_ary)
|
||||
Associations::HasMany
|
||||
else
|
||||
Associations::HasOne
|
||||
end
|
||||
|
||||
association = association_class.new(name, self, options)
|
||||
|
||||
if association.embed_ids?
|
||||
node[association.key] = association.serialize_ids
|
||||
|
||||
if association.embed_in_root? && hash.nil?
|
||||
raise IncludeError.new(self.class, association.name)
|
||||
elsif association.embed_in_root? && association.embeddable?
|
||||
merge_association hash, association.root, association.serializables, unique_values
|
||||
end
|
||||
elsif association.embed_objects?
|
||||
node[association.key] = association.serialize
|
||||
end
|
||||
end
|
||||
|
||||
# In some cases, an Array of associations is built by merging the associated
|
||||
# content for all of the children. For instance, if a Post has_many comments,
|
||||
# which has_many tags, the top-level :tags key will contain the merged list
|
||||
# of all tags for all comments of the post.
|
||||
#
|
||||
# In order to make this efficient, we store a :unique_values hash containing
|
||||
# a unique list of all of the objects that are already in the Array. This
|
||||
# avoids the need to scan through the Array looking for entries every time
|
||||
# we want to merge a new list of values.
|
||||
def merge_association(hash, key, serializables, unique_values)
|
||||
already_serialized = (unique_values[key] ||= {})
|
||||
serializable_hashes = (hash[key] ||= [])
|
||||
|
||||
serializables.each do |serializable|
|
||||
unless already_serialized.include? serializable.object
|
||||
already_serialized[serializable.object] = true
|
||||
serializable_hashes << serializable.serializable_hash
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a hash representation of the serializable
|
||||
# object attributes.
|
||||
def attributes
|
||||
_fast_attributes
|
||||
rescue NameError
|
||||
method = "def _fast_attributes\n"
|
||||
|
||||
method << " h = {}\n"
|
||||
|
||||
_attributes.each do |name,key|
|
||||
method << " h[:\"#{key}\"] = read_attribute_for_serialization(:\"#{name}\") if include?(:\"#{name}\")\n"
|
||||
end
|
||||
method << " h\nend"
|
||||
|
||||
self.class.class_eval method
|
||||
_fast_attributes
|
||||
end
|
||||
|
||||
# Returns options[:scope]
|
||||
def scope
|
||||
@options[:scope]
|
||||
end
|
||||
|
||||
alias :read_attribute_for_serialization :send
|
||||
|
||||
def _serializable_hash
|
||||
return nil if @object.nil?
|
||||
attributes
|
||||
end
|
||||
|
||||
def perform_caching?
|
||||
perform_caching && cache && respond_to?(:cache_key)
|
||||
end
|
||||
|
||||
def expand_cache_key(*args)
|
||||
ActiveSupport::Cache.expand_cache_key(args)
|
||||
end
|
||||
|
||||
# Use ActiveSupport::Notifications to send events to external systems.
|
||||
# The event name is: name.class_name.serializer
|
||||
def instrument(name, payload = {}, &block)
|
||||
event_name = INSTRUMENT[name]
|
||||
ActiveSupport::Notifications.instrument(event_name, payload, &block)
|
||||
end
|
||||
end
|
||||
|
||||
# DefaultSerializer
|
||||
#
|
||||
# Provides a constant interface for all items, particularly
|
||||
# for ArraySerializer.
|
||||
class DefaultSerializer
|
||||
attr_reader :object, :options
|
||||
|
||||
def initialize(object, options={})
|
||||
@object, @options = object, options
|
||||
end
|
||||
|
||||
def serializable_hash
|
||||
@object.as_json(@options)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,233 +0,0 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Associations #:nodoc:
|
||||
class Config #:nodoc:
|
||||
class_attribute :options
|
||||
|
||||
def self.refine(name, class_options)
|
||||
current_class = self
|
||||
|
||||
Class.new(self) do
|
||||
singleton_class.class_eval do
|
||||
define_method(:to_s) do
|
||||
"(subclass of #{current_class.name})"
|
||||
end
|
||||
|
||||
alias inspect to_s
|
||||
end
|
||||
|
||||
self.options = class_options
|
||||
|
||||
# cache the root so we can reuse it without falling back on a per-instance basis
|
||||
begin
|
||||
self.options[:root] ||= self.new(name, nil).root
|
||||
rescue
|
||||
# this could fail if it needs a valid source, for example a polymorphic association
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
self.options = {}
|
||||
|
||||
def initialize(name, source, options={})
|
||||
@name = name
|
||||
@source = source
|
||||
@options = options
|
||||
end
|
||||
|
||||
def option(key, default=nil)
|
||||
if @options.key?(key)
|
||||
@options[key]
|
||||
elsif self.class.options.key?(key)
|
||||
self.class.options[key]
|
||||
else
|
||||
default
|
||||
end
|
||||
end
|
||||
|
||||
def target_serializer
|
||||
serializer = option(:serializer)
|
||||
serializer.is_a?(String) ? serializer.constantize : serializer
|
||||
end
|
||||
|
||||
def source_serializer
|
||||
@source
|
||||
end
|
||||
|
||||
def key
|
||||
option(:key) || @name
|
||||
end
|
||||
|
||||
def root
|
||||
option(:root) || @name
|
||||
end
|
||||
|
||||
def name
|
||||
option(:name) || @name
|
||||
end
|
||||
|
||||
def associated_object
|
||||
option(:value) || source_serializer.send(name)
|
||||
end
|
||||
|
||||
def embed_ids?
|
||||
[:id, :ids].include? option(:embed, source_serializer._embed)
|
||||
end
|
||||
|
||||
def embed_objects?
|
||||
[:object, :objects].include? option(:embed, source_serializer._embed)
|
||||
end
|
||||
|
||||
def embed_in_root?
|
||||
option(:include, source_serializer._root_embed)
|
||||
end
|
||||
|
||||
def embeddable?
|
||||
!associated_object.nil?
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def find_serializable(object)
|
||||
if target_serializer
|
||||
target_serializer.new(object, source_serializer.options)
|
||||
elsif object.respond_to?(:active_model_serializer) && (ams = object.active_model_serializer)
|
||||
ams.new(object, source_serializer.options)
|
||||
else
|
||||
object
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class HasMany < Config #:nodoc:
|
||||
def key
|
||||
if key = option(:key)
|
||||
key
|
||||
elsif embed_ids?
|
||||
"#{@name.to_s.singularize}_ids".to_sym
|
||||
else
|
||||
@name
|
||||
end
|
||||
end
|
||||
|
||||
def embed_key
|
||||
if key = option(:embed_key)
|
||||
key
|
||||
else
|
||||
:id
|
||||
end
|
||||
end
|
||||
|
||||
def serialize
|
||||
associated_object.map do |item|
|
||||
find_serializable(item).serializable_hash
|
||||
end
|
||||
end
|
||||
|
||||
def serializables
|
||||
associated_object.map do |item|
|
||||
find_serializable(item)
|
||||
end
|
||||
end
|
||||
|
||||
def serialize_ids
|
||||
ids_key = "#{@name.to_s.singularize}_ids".to_sym
|
||||
if !option(:embed_key) && !source_serializer.respond_to?(@name.to_s) && source_serializer.object.respond_to?(ids_key)
|
||||
source_serializer.object.read_attribute_for_serialization(ids_key)
|
||||
else
|
||||
associated_object.map do |item|
|
||||
item.read_attribute_for_serialization(embed_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class HasOne < Config #:nodoc:
|
||||
def embeddable?
|
||||
if polymorphic? && associated_object.nil?
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def polymorphic?
|
||||
option :polymorphic
|
||||
end
|
||||
|
||||
def root
|
||||
if root = option(:root)
|
||||
root
|
||||
elsif polymorphic?
|
||||
associated_object.class.to_s.pluralize.demodulize.underscore.to_sym
|
||||
else
|
||||
@name.to_s.pluralize.to_sym
|
||||
end
|
||||
end
|
||||
|
||||
def key
|
||||
if key = option(:key)
|
||||
key
|
||||
elsif embed_ids? && !polymorphic?
|
||||
"#{@name}_id".to_sym
|
||||
else
|
||||
@name
|
||||
end
|
||||
end
|
||||
|
||||
def embed_key
|
||||
if key = option(:embed_key)
|
||||
key
|
||||
else
|
||||
:id
|
||||
end
|
||||
end
|
||||
|
||||
def polymorphic_key
|
||||
associated_object.class.to_s.demodulize.underscore.to_sym
|
||||
end
|
||||
|
||||
def serialize
|
||||
object = associated_object
|
||||
|
||||
if object && polymorphic?
|
||||
{
|
||||
:type => polymorphic_key,
|
||||
polymorphic_key => find_serializable(object).serializable_hash
|
||||
}
|
||||
elsif object
|
||||
find_serializable(object).serializable_hash
|
||||
end
|
||||
end
|
||||
|
||||
def serializables
|
||||
object = associated_object
|
||||
value = object && find_serializable(object)
|
||||
value ? [value] : []
|
||||
end
|
||||
|
||||
def serialize_ids
|
||||
id_key = "#{@name}_id".to_sym
|
||||
|
||||
if polymorphic?
|
||||
if associated_object
|
||||
{
|
||||
:type => polymorphic_key,
|
||||
:id => associated_object.read_attribute_for_serialization(embed_key)
|
||||
}
|
||||
else
|
||||
nil
|
||||
end
|
||||
elsif !option(:embed_key) && !source_serializer.respond_to?(@name.to_s) && source_serializer.object.respond_to?(id_key)
|
||||
source_serializer.object.read_attribute_for_serialization(id_key)
|
||||
elsif associated_object
|
||||
associated_object.read_attribute_for_serialization(embed_key)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,5 +0,0 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
VERSION = "0.8.4"
|
||||
end
|
||||
end
|
||||
@ -1,95 +0,0 @@
|
||||
require "active_support"
|
||||
require "active_support/core_ext/string/inflections"
|
||||
require "active_support/notifications"
|
||||
require "active_model"
|
||||
require "active_model/array_serializer"
|
||||
require "active_model/serializer"
|
||||
require "active_model/serializer/associations"
|
||||
require "set"
|
||||
|
||||
if defined?(Rails)
|
||||
module ActiveModel
|
||||
class Railtie < Rails::Railtie
|
||||
generators do |app|
|
||||
app ||= Rails.application # Rails 3.0.x does not yield `app`
|
||||
|
||||
Rails::Generators.configure!(app.config.generators)
|
||||
Rails::Generators.hidden_namespaces.uniq!
|
||||
require_relative "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
|
||||
|
||||
initializer "caching.active_model_serializer" do |app|
|
||||
ActiveModel::Serializer.perform_caching = app.config.action_controller.perform_caching
|
||||
ActiveModel::ArraySerializer.perform_caching = app.config.action_controller.perform_caching
|
||||
|
||||
ActiveModel::Serializer.cache = Rails.cache
|
||||
ActiveModel::ArraySerializer.cache = Rails.cache
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module ActiveModel::SerializerSupport
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods #:nodoc:
|
||||
if "".respond_to?(:safe_constantize)
|
||||
def active_model_serializer
|
||||
"#{self.name}Serializer".safe_constantize
|
||||
end
|
||||
else
|
||||
def active_model_serializer
|
||||
begin
|
||||
"#{self.name}Serializer".constantize
|
||||
rescue NameError => e
|
||||
raise unless e.message =~ /uninitialized constant/
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a model serializer for this object considering its namespace.
|
||||
def active_model_serializer
|
||||
self.class.active_model_serializer
|
||||
end
|
||||
|
||||
alias :read_attribute_for_serialization :send
|
||||
end
|
||||
|
||||
module ActiveModel::ArraySerializerSupport
|
||||
def active_model_serializer
|
||||
ActiveModel::ArraySerializer
|
||||
end
|
||||
end
|
||||
|
||||
Array.send(:include, ActiveModel::ArraySerializerSupport)
|
||||
Set.send(:include, ActiveModel::ArraySerializerSupport)
|
||||
|
||||
{
|
||||
:active_record => 'ActiveRecord::Relation',
|
||||
:mongoid => 'Mongoid::Criteria'
|
||||
}.each do |orm, rel_class|
|
||||
ActiveSupport.on_load(orm) do
|
||||
include ActiveModel::SerializerSupport
|
||||
rel_class.constantize.send(:include, ActiveModel::ArraySerializerSupport)
|
||||
end
|
||||
end
|
||||
|
||||
begin
|
||||
require 'action_controller'
|
||||
require 'action_controller/serialization'
|
||||
|
||||
ActiveSupport.on_load(:action_controller) do
|
||||
include ::ActionController::Serialization
|
||||
end
|
||||
rescue LoadError => ex
|
||||
# rails on installed, continuing
|
||||
end
|
||||
|
||||
ActiveSupport.run_load_hooks(:active_model_serializers, ActiveModel::Serializer)
|
||||
@ -1,16 +0,0 @@
|
||||
# We do not recommend that you use AM::S in this way, but if you must, here
|
||||
# is a mixin that overrides ActiveRecord::Base#to_json and #as_json.
|
||||
|
||||
module ActiveRecord
|
||||
module SerializerOverride
|
||||
def to_json options = {}
|
||||
active_model_serializer.new(self).to_json options
|
||||
end
|
||||
|
||||
def as_json options={}
|
||||
active_model_serializer.new(self).as_json options
|
||||
end
|
||||
end
|
||||
|
||||
Base.send(:include, SerializerOverride)
|
||||
end
|
||||
@ -1,13 +0,0 @@
|
||||
require "rails/generators"
|
||||
require "rails/generators/rails/resource/resource_generator"
|
||||
|
||||
module Rails
|
||||
module Generators
|
||||
ResourceGenerator.class_eval do
|
||||
def add_serializer
|
||||
invoke "serializer"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
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
|
||||
@ -1,42 +0,0 @@
|
||||
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 generate_id_method
|
||||
RUBY_VERSION =~ /1\.8/
|
||||
end
|
||||
|
||||
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]
|
||||
# Only works on 3.2
|
||||
# elsif (n = Rails::Generators.namespace) && n.const_defined?(:ApplicationSerializer)
|
||||
# "ApplicationSerializer"
|
||||
elsif defined?(::ApplicationSerializer)
|
||||
"ApplicationSerializer"
|
||||
else
|
||||
"ActiveModel::Serializer"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,19 +0,0 @@
|
||||
<% 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 -%>
|
||||
<% if generate_id_method %>
|
||||
|
||||
# due to the difference between 1.8 and 1.9 with respect to #id and
|
||||
# #object_id, we recommend that if you wish to serialize id columns, you
|
||||
# do this. Feel free to remove this if you don't feel that it's appropriate.
|
||||
#
|
||||
# For more: https://github.com/rails-api/active_model_serializers/issues/127
|
||||
def id
|
||||
object.read_attribute_for_serialization(:id)
|
||||
end
|
||||
<% end -%>
|
||||
end
|
||||
<% end -%>
|
||||
@ -1,75 +0,0 @@
|
||||
require "test_helper"
|
||||
require "test_fakes"
|
||||
|
||||
class ArraySerializerTest < ActiveModel::TestCase
|
||||
|
||||
def test_array_items_do_not_have_root
|
||||
array = [
|
||||
BasicActiveModel.new(:name => "First model"),
|
||||
BasicActiveModel.new(:name => "Second model")
|
||||
]
|
||||
expected = { "root" => [
|
||||
{ :name => "First model" },
|
||||
{ :name => "Second model" }
|
||||
] }
|
||||
|
||||
default_serializer = array.active_model_serializer.new(array, :root => "root")
|
||||
each_serializer = array.active_model_serializer.new(array, :root => "root", :each_serializer => BasicSerializer)
|
||||
|
||||
default_json = default_serializer.as_json
|
||||
each_json = each_serializer.as_json
|
||||
|
||||
assert_equal(expected, default_json)
|
||||
assert_equal(expected, each_json)
|
||||
end
|
||||
|
||||
# serialize different typed objects
|
||||
def test_array_serializer
|
||||
model = Model.new
|
||||
user = User.new
|
||||
comments = Comment.new(:title => "Comment1", :id => 1)
|
||||
|
||||
array = [model, user, comments]
|
||||
serializer = array.active_model_serializer.new(array, :scope => {:scope => true})
|
||||
assert_equal([
|
||||
{ :model => "Model" },
|
||||
{ :last_name => "Valim", :ok => true, :first_name => "Jose", :scope => true },
|
||||
{ :title => "Comment1" }
|
||||
], serializer.as_json)
|
||||
end
|
||||
|
||||
def test_array_serializer_with_root
|
||||
comment1 = Comment.new(:title => "Comment1", :id => 1)
|
||||
comment2 = Comment.new(:title => "Comment2", :id => 2)
|
||||
|
||||
array = [ comment1, comment2 ]
|
||||
|
||||
serializer = array.active_model_serializer.new(array, :root => :comments)
|
||||
|
||||
assert_equal({ :comments => [
|
||||
{ :title => "Comment1" },
|
||||
{ :title => "Comment2" }
|
||||
]}, serializer.as_json)
|
||||
end
|
||||
|
||||
def test_array_serializer_with_hash
|
||||
hash = {:value => "something"}
|
||||
array = [hash]
|
||||
serializer = array.active_model_serializer.new(array, :root => :items)
|
||||
assert_equal({ :items => [ hash.as_json ]}, serializer.as_json)
|
||||
end
|
||||
|
||||
def test_array_serializer_with_specified_seriailizer
|
||||
post1 = Post.new(:title => "Post1", :author => "Author1", :id => 1)
|
||||
post2 = Post.new(:title => "Post2", :author => "Author2", :id => 2)
|
||||
|
||||
array = [ post1, post2 ]
|
||||
|
||||
serializer = array.active_model_serializer.new array, :each_serializer => CustomPostSerializer
|
||||
|
||||
assert_equal([
|
||||
{ :title => "Post1" },
|
||||
{ :title => "Post2" }
|
||||
], serializer.as_json)
|
||||
end
|
||||
end
|
||||
@ -1,592 +0,0 @@
|
||||
require "test_helper"
|
||||
|
||||
class AssociationTest < ActiveModel::TestCase
|
||||
def def_serializer(&block)
|
||||
Class.new(ActiveModel::Serializer, &block)
|
||||
end
|
||||
|
||||
class Model
|
||||
def initialize(hash={})
|
||||
@attributes = hash
|
||||
end
|
||||
|
||||
def read_attribute_for_serialization(name)
|
||||
@attributes[name]
|
||||
end
|
||||
|
||||
def as_json(*)
|
||||
{ :model => "Model" }
|
||||
end
|
||||
|
||||
def method_missing(meth, *args)
|
||||
if meth.to_s =~ /^(.*)=$/
|
||||
@attributes[$1.to_sym] = args[0]
|
||||
elsif @attributes.key?(meth)
|
||||
@attributes[meth]
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def setup
|
||||
@hash = {}
|
||||
@root_hash = {}
|
||||
|
||||
@post = Model.new(:title => "New Post", :body => "Body")
|
||||
@comment = Model.new(:id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT")
|
||||
@post.comments = [ @comment ]
|
||||
@post.comment = @comment
|
||||
|
||||
@comment_serializer_class = def_serializer do
|
||||
attributes :id, :external_id, :body
|
||||
end
|
||||
|
||||
@post_serializer_class = def_serializer do
|
||||
attributes :title, :body
|
||||
end
|
||||
|
||||
@post_serializer = @post_serializer_class.new(@post, :hash => @root_hash)
|
||||
end
|
||||
|
||||
def include!(key, options={})
|
||||
@post_serializer.include! key, {
|
||||
:embed => :ids,
|
||||
:include => true,
|
||||
:node => @hash,
|
||||
:serializer => @comment_serializer_class
|
||||
}.merge(options)
|
||||
end
|
||||
|
||||
def include_bare!(key, options={})
|
||||
@post_serializer.include! key, {
|
||||
:node => @hash,
|
||||
:serializer => @comment_serializer_class
|
||||
}.merge(options)
|
||||
end
|
||||
|
||||
class NoDefaults < AssociationTest
|
||||
def test_include_bang_has_many_associations
|
||||
include! :comments, :value => @post.comments
|
||||
|
||||
assert_equal({
|
||||
:comment_ids => [ 1 ]
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
:comments => [
|
||||
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_include_bang_with_embed_false
|
||||
include! :comments, :value => @post.comments, :embed => false
|
||||
|
||||
assert_equal({}, @hash)
|
||||
assert_equal({}, @root_hash)
|
||||
end
|
||||
|
||||
def test_include_bang_with_embed_ids_include_false
|
||||
include! :comments, :value => @post.comments, :embed => :ids, :include => false
|
||||
|
||||
assert_equal({
|
||||
:comment_ids => [ 1 ]
|
||||
}, @hash)
|
||||
|
||||
assert_equal({}, @root_hash)
|
||||
end
|
||||
|
||||
def test_include_bang_has_one_associations
|
||||
include! :comment, :value => @post.comment
|
||||
|
||||
assert_equal({
|
||||
:comment_id => 1
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
:comments => [{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }]
|
||||
}, @root_hash)
|
||||
end
|
||||
end
|
||||
|
||||
class DefaultsTest < AssociationTest
|
||||
def test_with_default_has_many
|
||||
@post_serializer_class.class_eval do
|
||||
has_many :comments
|
||||
end
|
||||
|
||||
include! :comments
|
||||
|
||||
assert_equal({
|
||||
:comment_ids => [ 1 ]
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
:comments => [
|
||||
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_with_default_has_one
|
||||
@post_serializer_class.class_eval do
|
||||
has_one :comment
|
||||
end
|
||||
|
||||
include! :comment
|
||||
|
||||
assert_equal({
|
||||
:comment_id => 1
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
:comments => [
|
||||
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_with_default_has_many_with_custom_key
|
||||
@post_serializer_class.class_eval do
|
||||
has_many :comments, :key => :custom_comments
|
||||
end
|
||||
|
||||
include! :comments
|
||||
|
||||
assert_equal({
|
||||
:custom_comments => [ 1 ]
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
:comments => [
|
||||
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_with_default_has_one_with_custom_key
|
||||
@post_serializer_class.class_eval do
|
||||
has_one :comment, :key => :custom_comment_id
|
||||
end
|
||||
|
||||
include! :comment
|
||||
|
||||
assert_equal({
|
||||
:custom_comment_id => 1
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
:comments => [
|
||||
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_with_default_has_many_with_custom_embed_key
|
||||
@post_serializer_class.class_eval do
|
||||
has_many :comments, :embed_key => :external_id
|
||||
end
|
||||
|
||||
include! :comments
|
||||
|
||||
assert_equal({
|
||||
:comment_ids => [ "COMM001" ]
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
:comments => [
|
||||
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_with_default_has_one_with_custom_embed_key
|
||||
@post_serializer_class.class_eval do
|
||||
has_one :comment, :embed_key => :external_id
|
||||
end
|
||||
|
||||
include! :comment
|
||||
|
||||
assert_equal({
|
||||
:comment_id => "COMM001"
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
:comments => [
|
||||
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_with_default_has_many_with_custom_key_and_custom_embed_key
|
||||
@post_serializer_class.class_eval do
|
||||
has_many :comments, :key => :custom_comments, :embed_key => :external_id
|
||||
end
|
||||
|
||||
include! :comments
|
||||
|
||||
assert_equal({
|
||||
:custom_comments => [ "COMM001" ]
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
:comments => [
|
||||
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_with_default_has_one_with_custom_key_and_custom_embed_key
|
||||
@post_serializer_class.class_eval do
|
||||
has_one :comment, :key => :custom_comment, :embed_key => :external_id
|
||||
end
|
||||
|
||||
include! :comment
|
||||
|
||||
assert_equal({
|
||||
:custom_comment => "COMM001"
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
:comments => [
|
||||
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_embed_objects_for_has_many_associations
|
||||
@post_serializer_class.class_eval do
|
||||
has_many :comments, :embed => :objects
|
||||
end
|
||||
|
||||
include_bare! :comments
|
||||
|
||||
assert_equal({
|
||||
:comments => [
|
||||
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @hash)
|
||||
|
||||
assert_equal({}, @root_hash)
|
||||
end
|
||||
|
||||
def test_embed_ids_for_has_many_associations
|
||||
@post_serializer_class.class_eval do
|
||||
has_many :comments, :embed => :ids
|
||||
end
|
||||
|
||||
include_bare! :comments
|
||||
|
||||
assert_equal({
|
||||
:comment_ids => [ 1 ]
|
||||
}, @hash)
|
||||
|
||||
assert_equal({}, @root_hash)
|
||||
end
|
||||
|
||||
def test_embed_false_for_has_many_associations
|
||||
@post_serializer_class.class_eval do
|
||||
has_many :comments, :embed => false
|
||||
end
|
||||
|
||||
include_bare! :comments
|
||||
|
||||
assert_equal({}, @hash)
|
||||
assert_equal({}, @root_hash)
|
||||
end
|
||||
|
||||
def test_embed_ids_include_true_for_has_many_associations
|
||||
@post_serializer_class.class_eval do
|
||||
has_many :comments, :embed => :ids, :include => true
|
||||
end
|
||||
|
||||
include_bare! :comments
|
||||
|
||||
assert_equal({
|
||||
:comment_ids => [ 1 ]
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
:comments => [
|
||||
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_embed_ids_for_has_one_associations
|
||||
@post_serializer_class.class_eval do
|
||||
has_one :comment, :embed => :ids
|
||||
end
|
||||
|
||||
include_bare! :comment
|
||||
|
||||
assert_equal({
|
||||
:comment_id => 1
|
||||
}, @hash)
|
||||
|
||||
assert_equal({}, @root_hash)
|
||||
end
|
||||
|
||||
def test_embed_false_for_has_one_associations
|
||||
@post_serializer_class.class_eval do
|
||||
has_one :comment, :embed => false
|
||||
end
|
||||
|
||||
include_bare! :comment
|
||||
|
||||
assert_equal({}, @hash)
|
||||
assert_equal({}, @root_hash)
|
||||
end
|
||||
|
||||
def test_embed_ids_include_true_for_has_one_associations
|
||||
@post_serializer_class.class_eval do
|
||||
has_one :comment, :embed => :ids, :include => true
|
||||
end
|
||||
|
||||
include_bare! :comment
|
||||
|
||||
assert_equal({
|
||||
:comment_id => 1
|
||||
}, @hash)
|
||||
|
||||
assert_equal({
|
||||
:comments => [
|
||||
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @root_hash)
|
||||
end
|
||||
|
||||
def test_embed_ids_include_true_does_not_serialize_multiple_times
|
||||
@post.recent_comment = @comment
|
||||
|
||||
@post_serializer_class.class_eval do
|
||||
has_one :comment, :embed => :ids, :include => true
|
||||
has_one :recent_comment, :embed => :ids, :include => true, :root => :comments
|
||||
end
|
||||
|
||||
# Count how often the @comment record is serialized.
|
||||
serialized_times = 0
|
||||
@comment.class_eval do
|
||||
define_method :read_attribute_for_serialization, lambda { |name|
|
||||
serialized_times += 1 if name == :body
|
||||
super(name)
|
||||
}
|
||||
end
|
||||
|
||||
include_bare! :comment
|
||||
include_bare! :recent_comment
|
||||
|
||||
assert_equal 1, serialized_times
|
||||
end
|
||||
|
||||
def test_include_with_read_association_id_for_serialization_hook
|
||||
@post_serializer_class.class_eval do
|
||||
has_one :comment, :embed => :ids, :include => true
|
||||
end
|
||||
|
||||
association_name = nil
|
||||
@post.class_eval do
|
||||
define_method :read_attribute_for_serialization, lambda { |name|
|
||||
association_name = name
|
||||
send(name)
|
||||
}
|
||||
define_method :comment_id, lambda {
|
||||
@attributes[:comment].id
|
||||
}
|
||||
end
|
||||
|
||||
include_bare! :comment
|
||||
|
||||
assert_equal({
|
||||
:comment_id => 1
|
||||
}, @hash)
|
||||
end
|
||||
|
||||
def test_include_with_read_association_ids_for_serialization_hook
|
||||
@post_serializer_class.class_eval do
|
||||
has_many :comments, :embed => :ids, :include => false
|
||||
end
|
||||
|
||||
association_name = nil
|
||||
@post.class_eval do
|
||||
define_method :read_attribute_for_serialization, lambda { |name|
|
||||
association_name = name
|
||||
send(name)
|
||||
}
|
||||
define_method :comment_ids, lambda {
|
||||
@attributes[:comments].map(&:id)
|
||||
}
|
||||
end
|
||||
|
||||
include_bare! :comments
|
||||
|
||||
assert_equal({
|
||||
:comment_ids => [1]
|
||||
}, @hash)
|
||||
end
|
||||
end
|
||||
|
||||
class RecursiveTest < AssociationTest
|
||||
class BarSerializer < ActiveModel::Serializer; end
|
||||
|
||||
class FooSerializer < ActiveModel::Serializer
|
||||
root :foos
|
||||
attributes :id
|
||||
has_many :bars, :serializer => BarSerializer, :root => :bars, :embed => :ids, :include => true
|
||||
end
|
||||
|
||||
class BarSerializer < ActiveModel::Serializer
|
||||
root :bars
|
||||
attributes :id
|
||||
has_many :foos, :serializer => FooSerializer, :root => :foos, :embed => :ids, :include => true
|
||||
end
|
||||
|
||||
class Foo < Model
|
||||
def active_model_serializer; FooSerializer; end
|
||||
end
|
||||
|
||||
class Bar < Model
|
||||
def active_model_serializer; BarSerializer; end
|
||||
end
|
||||
|
||||
def setup
|
||||
super
|
||||
|
||||
foo = Foo.new(:id => 1)
|
||||
bar = Bar.new(:id => 2)
|
||||
|
||||
foo.bars = [ bar ]
|
||||
bar.foos = [ foo ]
|
||||
|
||||
collection = [ foo ]
|
||||
|
||||
@serializer = collection.active_model_serializer.new(collection, :root => :foos)
|
||||
end
|
||||
|
||||
def test_mutual_relation_result
|
||||
assert_equal({
|
||||
:foos => [{
|
||||
:bar_ids => [ 2 ],
|
||||
:id => 1
|
||||
}],
|
||||
:bars => [{
|
||||
:foo_ids => [ 1 ],
|
||||
:id => 2
|
||||
}]
|
||||
}, @serializer.as_json)
|
||||
end
|
||||
|
||||
def test_mutual_relation_does_not_raise_error
|
||||
assert_nothing_raised SystemStackError, 'stack level too deep' do
|
||||
@serializer.as_json
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class InclusionTest < AssociationTest
|
||||
def setup
|
||||
super
|
||||
|
||||
comment_serializer_class = @comment_serializer_class
|
||||
|
||||
@post_serializer_class.class_eval do
|
||||
root :post
|
||||
embed :ids, :include => true
|
||||
has_many :comments, :serializer => comment_serializer_class
|
||||
end
|
||||
end
|
||||
|
||||
def test_when_it_is_included
|
||||
post_serializer = @post_serializer_class.new(
|
||||
@post, :include => [:comments]
|
||||
)
|
||||
|
||||
json = post_serializer.as_json
|
||||
|
||||
assert_equal({
|
||||
:post => {
|
||||
:title => "New Post",
|
||||
:body => "Body",
|
||||
:comment_ids => [ 1 ]
|
||||
},
|
||||
:comments => [
|
||||
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
|
||||
]
|
||||
}, json)
|
||||
end
|
||||
|
||||
def test_when_it_is_not_included
|
||||
post_serializer = @post_serializer_class.new(
|
||||
@post, :include => []
|
||||
)
|
||||
|
||||
json = post_serializer.as_json
|
||||
|
||||
assert_equal({
|
||||
:post => {
|
||||
:title => "New Post",
|
||||
:body => "Body",
|
||||
:comment_ids => [ 1 ]
|
||||
}
|
||||
}, json)
|
||||
end
|
||||
|
||||
def test_when_it_is_excluded
|
||||
post_serializer = @post_serializer_class.new(
|
||||
@post, :exclude => [:comments]
|
||||
)
|
||||
|
||||
json = post_serializer.as_json
|
||||
|
||||
assert_equal({
|
||||
:post => {
|
||||
:title => "New Post",
|
||||
:body => "Body",
|
||||
:comment_ids => [ 1 ]
|
||||
}
|
||||
}, json)
|
||||
end
|
||||
|
||||
def test_when_it_is_not_excluded
|
||||
post_serializer = @post_serializer_class.new(
|
||||
@post, :exclude => []
|
||||
)
|
||||
|
||||
json = post_serializer.as_json
|
||||
|
||||
assert_equal({
|
||||
:post => {
|
||||
:title => "New Post",
|
||||
:body => "Body",
|
||||
:comment_ids => [ 1 ]
|
||||
},
|
||||
:comments => [
|
||||
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
|
||||
]
|
||||
}, json)
|
||||
end
|
||||
end
|
||||
|
||||
class StringSerializerOption < AssociationTest
|
||||
class StringSerializer < ActiveModel::Serializer
|
||||
attributes :id, :body
|
||||
end
|
||||
|
||||
def test_specifying_serializer_class_as_string
|
||||
@post_serializer_class.class_eval do
|
||||
has_many :comments, :embed => :objects
|
||||
end
|
||||
|
||||
include_bare! :comments, :serializer => "AssociationTest::StringSerializerOption::StringSerializer"
|
||||
|
||||
assert_equal({
|
||||
:comments => [
|
||||
{ :id => 1, :body => "ZOMG A COMMENT" }
|
||||
]
|
||||
}, @hash)
|
||||
|
||||
assert_equal({}, @root_hash)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,177 +0,0 @@
|
||||
require "test_helper"
|
||||
|
||||
class CachingTest < ActiveModel::TestCase
|
||||
class NullStore
|
||||
def fetch(key)
|
||||
return store[key] if store[key]
|
||||
|
||||
store[key] = yield
|
||||
end
|
||||
|
||||
def clear
|
||||
store.clear
|
||||
end
|
||||
|
||||
def store
|
||||
@store ||= {}
|
||||
end
|
||||
|
||||
def read(key)
|
||||
store[key]
|
||||
end
|
||||
end
|
||||
|
||||
class Programmer
|
||||
def name
|
||||
'Adam'
|
||||
end
|
||||
|
||||
def skills
|
||||
%w(ruby)
|
||||
end
|
||||
|
||||
def read_attribute_for_serialization(name)
|
||||
send name
|
||||
end
|
||||
end
|
||||
|
||||
class Parent
|
||||
def id
|
||||
'parent1'
|
||||
end
|
||||
|
||||
def name
|
||||
'Kieran'
|
||||
end
|
||||
|
||||
def children
|
||||
[ Child.new ]
|
||||
end
|
||||
|
||||
def read_attribute_for_serialization(name)
|
||||
send name
|
||||
end
|
||||
end
|
||||
|
||||
class Child
|
||||
def id
|
||||
'child1'
|
||||
end
|
||||
|
||||
def name
|
||||
'Joshua'
|
||||
end
|
||||
|
||||
def parent
|
||||
Parent.new
|
||||
end
|
||||
|
||||
def read_attribute_for_serialization(name)
|
||||
send name
|
||||
end
|
||||
end
|
||||
|
||||
def test_serializers_have_a_cache_store
|
||||
ActiveModel::Serializer.cache = NullStore.new
|
||||
|
||||
assert_kind_of NullStore, ActiveModel::Serializer.cache
|
||||
end
|
||||
|
||||
def test_serializers_can_enable_caching
|
||||
serializer = Class.new(ActiveModel::Serializer) do
|
||||
cached true
|
||||
end
|
||||
|
||||
assert serializer.perform_caching
|
||||
end
|
||||
|
||||
def test_serializers_use_cache
|
||||
serializer = Class.new(ActiveModel::Serializer) do
|
||||
cached true
|
||||
attributes :name, :skills
|
||||
|
||||
def self.to_s
|
||||
'serializer'
|
||||
end
|
||||
|
||||
def cache_key
|
||||
object.name
|
||||
end
|
||||
end
|
||||
|
||||
serializer.cache = NullStore.new
|
||||
instance = serializer.new Programmer.new
|
||||
|
||||
instance.to_json
|
||||
|
||||
assert_equal(instance.serializable_hash, serializer.cache.read('serializer/Adam/serializable-hash'))
|
||||
assert_equal(instance.to_json, serializer.cache.read('serializer/Adam/to-json'))
|
||||
end
|
||||
|
||||
def test_array_serializer_uses_cache
|
||||
serializer = Class.new(ActiveModel::ArraySerializer) do
|
||||
cached true
|
||||
|
||||
def self.to_s
|
||||
'array_serializer'
|
||||
end
|
||||
|
||||
def cache_key
|
||||
'cache-key'
|
||||
end
|
||||
end
|
||||
|
||||
serializer.cache = NullStore.new
|
||||
instance = serializer.new [Programmer.new]
|
||||
|
||||
instance.to_json
|
||||
|
||||
assert_equal instance.serializable_array, serializer.cache.read('array_serializer/cache-key/serializable-array')
|
||||
assert_equal instance.to_json, serializer.cache.read('array_serializer/cache-key/to-json')
|
||||
end
|
||||
|
||||
def test_cached_serializers_return_associations
|
||||
|
||||
child_serializer = Class.new(ActiveModel::Serializer) do
|
||||
cached true
|
||||
attributes :name
|
||||
|
||||
def self.to_s
|
||||
'child_serializer'
|
||||
end
|
||||
|
||||
def cache_key
|
||||
object.name
|
||||
end
|
||||
end
|
||||
|
||||
parent_serializer = Class.new(ActiveModel::Serializer) do
|
||||
cached true
|
||||
attributes :name
|
||||
|
||||
has_many :children, serializer: child_serializer, embed: :ids, include: true
|
||||
|
||||
def self.to_s
|
||||
'parent_serializer'
|
||||
end
|
||||
|
||||
def cache_key
|
||||
object.name
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
parent_serializer.cache = NullStore.new
|
||||
child_serializer.cache = NullStore.new
|
||||
|
||||
instance = parent_serializer.new Parent.new, root: :parent
|
||||
|
||||
initial_keys = instance.as_json.keys
|
||||
|
||||
assert_equal(initial_keys, [:children, :parent])
|
||||
|
||||
cached_keys = instance.as_json.keys
|
||||
|
||||
assert_equal(cached_keys, [:children, :parent])
|
||||
end
|
||||
end
|
||||
@ -1,85 +0,0 @@
|
||||
require 'test_helper'
|
||||
|
||||
class Foo < Rails::Application
|
||||
if Rails.version.to_s.start_with? '4'
|
||||
config.eager_load = false
|
||||
config.secret_key_base = 'abc123'
|
||||
end
|
||||
end
|
||||
|
||||
Rails.application.load_generators
|
||||
|
||||
require 'generators/serializer/serializer_generator'
|
||||
|
||||
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
|
||||
run_generator
|
||||
assert_file "app/serializers/account_serializer.rb", /class AccountSerializer < ActiveModel::Serializer/
|
||||
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_serializer_gets_id
|
||||
run_generator
|
||||
|
||||
assert_file "app/serializers/account_serializer.rb" do |content|
|
||||
if RUBY_VERSION =~ /1.8/
|
||||
assert_match /def id/, content
|
||||
else
|
||||
assert_no_match /def id/, content
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# def test_uses_namespace_application_serializer_if_one_exists
|
||||
# Object.const_set(:SerializerNamespace, Module.new)
|
||||
# SerializerNamespace.const_set(:ApplicationSerializer, Class.new)
|
||||
# Rails::Generators.namespace = SerializerNamespace
|
||||
# run_generator
|
||||
# assert_file "app/serializers/serializer_namespace/account_serializer.rb",
|
||||
# /module SerializerNamespace\n class AccountSerializer < ApplicationSerializer/
|
||||
# ensure
|
||||
# Object.send :remove_const, :SerializerNamespace
|
||||
# Rails::Generators.namespace = nil
|
||||
# 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
|
||||
|
||||
def test_generates_attributes_and_associations
|
||||
run_generator
|
||||
assert_file "app/serializers/account_serializer.rb" do |serializer|
|
||||
assert_match(/^ attributes :id, :name, :description$/, serializer)
|
||||
assert_match(/^ has_one :business$/, serializer)
|
||||
end
|
||||
end
|
||||
|
||||
def test_with_no_attributes_does_not_add_extra_space
|
||||
run_generator ["account"]
|
||||
assert_file "app/serializers/account_serializer.rb" do |content|
|
||||
assert_no_match /\n\nend/, content
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,34 +0,0 @@
|
||||
require "test_helper"
|
||||
|
||||
class NoSerializationScopeTest < ActionController::TestCase
|
||||
class ScopeSerializer
|
||||
def initialize(object, options)
|
||||
@object, @options = object, options
|
||||
end
|
||||
|
||||
def as_json(*)
|
||||
{ :scope => @options[:scope].as_json }
|
||||
end
|
||||
end
|
||||
|
||||
class ScopeSerializable
|
||||
def active_model_serializer
|
||||
ScopeSerializer
|
||||
end
|
||||
end
|
||||
|
||||
class NoSerializationScopeController < ActionController::Base
|
||||
serialization_scope nil
|
||||
|
||||
def index
|
||||
render :json => ScopeSerializable.new
|
||||
end
|
||||
end
|
||||
|
||||
tests NoSerializationScopeController
|
||||
|
||||
def test_disabled_serialization_scope
|
||||
get :index, :format => :json
|
||||
assert_equal '{"scope":null}', @response.body
|
||||
end
|
||||
end
|
||||
@ -1,67 +0,0 @@
|
||||
require 'test_helper'
|
||||
require 'pathname'
|
||||
|
||||
class DefaultScopeNameTest < ActionController::TestCase
|
||||
TestUser = Struct.new(:name, :admin)
|
||||
|
||||
class UserSerializer < ActiveModel::Serializer
|
||||
attributes :admin?
|
||||
def admin?
|
||||
current_user.admin
|
||||
end
|
||||
end
|
||||
|
||||
class UserTestController < ActionController::Base
|
||||
protect_from_forgery
|
||||
|
||||
before_filter { request.format = :json }
|
||||
|
||||
def current_user
|
||||
TestUser.new('Pete', false)
|
||||
end
|
||||
|
||||
def render_new_user
|
||||
render :json => TestUser.new('pete', false), :serializer => UserSerializer
|
||||
end
|
||||
end
|
||||
|
||||
tests UserTestController
|
||||
|
||||
def test_default_scope_name
|
||||
get :render_new_user
|
||||
assert_equal '{"user":{"admin":false}}', @response.body
|
||||
end
|
||||
end
|
||||
|
||||
class SerializationScopeNameTest < ActionController::TestCase
|
||||
TestUser = Struct.new(:name, :admin)
|
||||
|
||||
class AdminUserSerializer < ActiveModel::Serializer
|
||||
attributes :admin?
|
||||
def admin?
|
||||
current_admin.admin
|
||||
end
|
||||
end
|
||||
|
||||
class AdminUserTestController < ActionController::Base
|
||||
protect_from_forgery
|
||||
|
||||
serialization_scope :current_admin
|
||||
before_filter { request.format = :json }
|
||||
|
||||
def current_admin
|
||||
TestUser.new('Bob', true)
|
||||
end
|
||||
|
||||
def render_new_user
|
||||
render :json => TestUser.new('pete', false), :serializer => AdminUserSerializer
|
||||
end
|
||||
end
|
||||
|
||||
tests AdminUserTestController
|
||||
|
||||
def test_override_scope_name_with_controller
|
||||
get :render_new_user
|
||||
assert_equal '{"admin_user":{"admin":true}}', @response.body
|
||||
end
|
||||
end
|
||||
@ -1,396 +0,0 @@
|
||||
require 'test_helper'
|
||||
require 'pathname'
|
||||
|
||||
class RenderJsonTest < ActionController::TestCase
|
||||
class JsonRenderable
|
||||
def as_json(options={})
|
||||
hash = { :a => :b, :c => :d, :e => :f }
|
||||
hash.except!(*options[:except]) if options[:except]
|
||||
hash
|
||||
end
|
||||
|
||||
def to_json(options = {})
|
||||
super :except => [:c, :e]
|
||||
end
|
||||
end
|
||||
|
||||
class JsonSerializer
|
||||
def initialize(object, options={})
|
||||
@object, @options = object, options
|
||||
end
|
||||
|
||||
def as_json(*)
|
||||
hash = { :object => serializable_hash, :scope => @options[:scope].as_json }
|
||||
hash.merge!(:options => true) if @options[:options]
|
||||
hash.merge!(:check_defaults => true) if @options[:check_defaults]
|
||||
hash
|
||||
end
|
||||
|
||||
def serializable_hash
|
||||
@object.as_json
|
||||
end
|
||||
end
|
||||
|
||||
class JsonSerializable
|
||||
def initialize(skip=false)
|
||||
@skip = skip
|
||||
end
|
||||
|
||||
def active_model_serializer
|
||||
JsonSerializer unless @skip
|
||||
end
|
||||
|
||||
def as_json(*)
|
||||
{ :serializable_object => true }
|
||||
end
|
||||
end
|
||||
|
||||
class CustomSerializer
|
||||
def initialize(*)
|
||||
end
|
||||
|
||||
def as_json(*)
|
||||
{ :hello => true }
|
||||
end
|
||||
end
|
||||
|
||||
class AnotherCustomSerializer
|
||||
def initialize(*)
|
||||
end
|
||||
|
||||
def as_json(*)
|
||||
{ :rails => 'rocks' }
|
||||
end
|
||||
end
|
||||
|
||||
class DummyCustomSerializer < ActiveModel::Serializer
|
||||
attributes :id
|
||||
end
|
||||
|
||||
class HypermediaSerializable
|
||||
def active_model_serializer
|
||||
HypermediaSerializer
|
||||
end
|
||||
end
|
||||
|
||||
class HypermediaSerializer < ActiveModel::Serializer
|
||||
def as_json(*)
|
||||
{ :link => hypermedia_url }
|
||||
end
|
||||
end
|
||||
|
||||
class CustomArraySerializer < ActiveModel::ArraySerializer
|
||||
self.root = "items"
|
||||
end
|
||||
|
||||
class TestController < ActionController::Base
|
||||
serialization_scope :current_user
|
||||
attr_reader :current_user
|
||||
|
||||
def self.controller_path
|
||||
'test'
|
||||
end
|
||||
|
||||
def render_json_nil
|
||||
render :json => nil
|
||||
end
|
||||
|
||||
def render_json_render_to_string
|
||||
render :text => render_to_string(:json => '[]')
|
||||
end
|
||||
|
||||
def render_json_hello_world
|
||||
render :json => ActiveSupport::JSON.encode(:hello => 'world')
|
||||
end
|
||||
|
||||
def render_json_hello_world_with_status
|
||||
render :json => ActiveSupport::JSON.encode(:hello => 'world'), :status => 401
|
||||
end
|
||||
|
||||
def render_json_hello_world_with_callback
|
||||
render :json => ActiveSupport::JSON.encode(:hello => 'world'), :callback => 'alert'
|
||||
end
|
||||
|
||||
def render_json_with_custom_content_type
|
||||
render :json => ActiveSupport::JSON.encode(:hello => 'world'), :content_type => 'text/javascript'
|
||||
end
|
||||
|
||||
def render_symbol_json
|
||||
render :json => ActiveSupport::JSON.encode(:hello => 'world')
|
||||
end
|
||||
|
||||
def render_json_nil_with_custom_serializer
|
||||
render :json => nil, :serializer => DummyCustomSerializer
|
||||
end
|
||||
|
||||
|
||||
def render_json_with_extra_options
|
||||
render :json => JsonRenderable.new, :except => [:c, :e]
|
||||
end
|
||||
|
||||
def render_json_without_options
|
||||
render :json => JsonRenderable.new
|
||||
end
|
||||
|
||||
def render_json_with_serializer
|
||||
@current_user = Struct.new(:as_json).new(:current_user => true)
|
||||
render :json => JsonSerializable.new
|
||||
end
|
||||
|
||||
def render_json_with_serializer_and_implicit_root
|
||||
@current_user = Struct.new(:as_json).new(:current_user => true)
|
||||
render :json => [JsonSerializable.new]
|
||||
end
|
||||
|
||||
def render_json_with_serializer_and_options
|
||||
@current_user = Struct.new(:as_json).new(:current_user => true)
|
||||
render :json => JsonSerializable.new, :options => true
|
||||
end
|
||||
|
||||
def render_json_with_serializer_and_scope_option
|
||||
@current_user = Struct.new(:as_json).new(:current_user => true)
|
||||
scope = Struct.new(:as_json).new(:current_user => false)
|
||||
render :json => JsonSerializable.new, :scope => scope
|
||||
end
|
||||
|
||||
def render_json_with_serializer_api_but_without_serializer
|
||||
@current_user = Struct.new(:as_json).new(:current_user => true)
|
||||
render :json => JsonSerializable.new(true)
|
||||
end
|
||||
|
||||
# To specify a custom serializer for an object, use :serializer.
|
||||
def render_json_with_custom_serializer
|
||||
render :json => Object.new, :serializer => CustomSerializer
|
||||
end
|
||||
|
||||
# To specify a custom serializer for each item in the Array, use :each_serializer.
|
||||
def render_json_array_with_custom_serializer
|
||||
render :json => [Object.new], :each_serializer => CustomSerializer
|
||||
end
|
||||
|
||||
def render_json_array_with_wrong_option
|
||||
render :json => [Object.new], :serializer => CustomSerializer
|
||||
end
|
||||
|
||||
def render_json_with_links
|
||||
render :json => HypermediaSerializable.new
|
||||
end
|
||||
|
||||
def render_json_array_with_no_root
|
||||
render :json => [], :root => false
|
||||
end
|
||||
|
||||
def render_json_empty_array
|
||||
render :json => []
|
||||
end
|
||||
|
||||
def render_json_array_with_custom_array_serializer
|
||||
render :json => [], :serializer => CustomArraySerializer
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def default_serializer_options
|
||||
defaults = {}
|
||||
defaults.merge!(:check_defaults => true) if params[:check_defaults]
|
||||
defaults.merge!(:root => :awesome) if params[:check_default_root]
|
||||
defaults.merge!(:scope => :current_admin) if params[:check_default_scope]
|
||||
defaults.merge!(:serializer => AnotherCustomSerializer) if params[:check_default_serializer]
|
||||
defaults.merge!(:each_serializer => AnotherCustomSerializer) if params[:check_default_each_serializer]
|
||||
defaults
|
||||
end
|
||||
end
|
||||
|
||||
tests TestController
|
||||
|
||||
def setup
|
||||
# enable a logger so that (e.g.) the benchmarking stuff runs, so we can get
|
||||
# a more accurate simulation of what happens in "real life".
|
||||
super
|
||||
@controller.logger = Logger.new(nil)
|
||||
|
||||
@request.host = "www.nextangle.com"
|
||||
end
|
||||
|
||||
def test_render_json_nil
|
||||
get :render_json_nil
|
||||
assert_equal 'null', @response.body
|
||||
assert_equal 'application/json', @response.content_type
|
||||
end
|
||||
|
||||
def test_render_json_render_to_string
|
||||
get :render_json_render_to_string
|
||||
assert_equal '[]', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_nil_with_custom_serializer
|
||||
get :render_json_nil_with_custom_serializer
|
||||
assert_equal "{\"dummy_custom\":null}", @response.body
|
||||
end
|
||||
|
||||
def test_render_json
|
||||
get :render_json_hello_world
|
||||
assert_equal '{"hello":"world"}', @response.body
|
||||
assert_equal 'application/json', @response.content_type
|
||||
end
|
||||
|
||||
def test_render_json_with_status
|
||||
get :render_json_hello_world_with_status
|
||||
assert_equal '{"hello":"world"}', @response.body
|
||||
assert_equal 401, @response.status
|
||||
end
|
||||
|
||||
def test_render_json_with_callback
|
||||
get :render_json_hello_world_with_callback
|
||||
if Rails::VERSION::MAJOR == 3
|
||||
assert_equal 'alert({"hello":"world"})', @response.body
|
||||
assert_match %r(application/json), @response.content_type.to_s
|
||||
else
|
||||
assert_equal '/**/alert({"hello":"world"})', @response.body
|
||||
assert_match %r(text/javascript), @response.content_type.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def test_render_json_with_custom_content_type
|
||||
get :render_json_with_custom_content_type
|
||||
assert_equal '{"hello":"world"}', @response.body
|
||||
assert_equal 'text/javascript', @response.content_type
|
||||
end
|
||||
|
||||
def test_render_symbol_json
|
||||
get :render_symbol_json
|
||||
assert_equal '{"hello":"world"}', @response.body
|
||||
assert_equal 'application/json', @response.content_type
|
||||
end
|
||||
|
||||
def test_render_json_forwards_extra_options
|
||||
get :render_json_with_extra_options
|
||||
assert_equal '{"a":"b"}', @response.body
|
||||
assert_equal 'application/json', @response.content_type
|
||||
end
|
||||
|
||||
def test_render_json_calls_to_json_from_object
|
||||
get :render_json_without_options
|
||||
assert_equal '{"a":"b"}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_serializer
|
||||
get :render_json_with_serializer
|
||||
assert_match '"scope":{"current_user":true}', @response.body
|
||||
assert_match '"object":{"serializable_object":true}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_serializer_checking_defaults
|
||||
get :render_json_with_serializer, :check_defaults => true
|
||||
assert_match '"scope":{"current_user":true}', @response.body
|
||||
assert_match '"object":{"serializable_object":true}', @response.body
|
||||
assert_match '"check_defaults":true', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_serializer_checking_default_serailizer
|
||||
get :render_json_with_serializer, :check_default_serializer => true
|
||||
assert_match '{"rails":"rocks"}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_serializer_checking_default_scope
|
||||
get :render_json_with_serializer, :check_default_scope => true
|
||||
assert_match '"scope":"current_admin"', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_serializer_and_implicit_root
|
||||
get :render_json_with_serializer_and_implicit_root
|
||||
assert_match '"test":[{"serializable_object":true}]', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_serializer_and_implicit_root_checking_default_each_serailizer
|
||||
get :render_json_with_serializer_and_implicit_root, :check_default_each_serializer => true
|
||||
assert_match '"test":[{"rails":"rocks"}]', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_serializer_and_options
|
||||
get :render_json_with_serializer_and_options
|
||||
assert_match '"scope":{"current_user":true}', @response.body
|
||||
assert_match '"object":{"serializable_object":true}', @response.body
|
||||
assert_match '"options":true', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_serializer_and_scope_option
|
||||
get :render_json_with_serializer_and_scope_option
|
||||
assert_match '"scope":{"current_user":false}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_serializer_and_scope_option_checking_default_scope
|
||||
get :render_json_with_serializer_and_scope_option, :check_default_scope => true
|
||||
assert_match '"scope":{"current_user":false}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_serializer_api_but_without_serializer
|
||||
get :render_json_with_serializer_api_but_without_serializer
|
||||
assert_match '{"serializable_object":true}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_custom_serializer
|
||||
get :render_json_with_custom_serializer
|
||||
assert_match '{"hello":true}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_custom_serializer_checking_default_serailizer
|
||||
get :render_json_with_custom_serializer, :check_default_serializer => true
|
||||
assert_match '{"hello":true}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_array_with_custom_serializer
|
||||
get :render_json_array_with_custom_serializer
|
||||
assert_match '{"test":[{"hello":true}]}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_array_with_wrong_option
|
||||
assert_raise ArgumentError do
|
||||
get :render_json_array_with_wrong_option
|
||||
end
|
||||
end
|
||||
|
||||
def test_render_json_array_with_custom_serializer_checking_default_each_serailizer
|
||||
get :render_json_array_with_custom_serializer, :check_default_each_serializer => true
|
||||
assert_match '{"test":[{"hello":true}]}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_with_links
|
||||
get :render_json_with_links
|
||||
assert_match '{"link":"http://www.nextangle.com/hypermedia"}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_array_with_no_root
|
||||
get :render_json_array_with_no_root
|
||||
assert_equal '[]', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_array_with_no_root_checking_default_root
|
||||
get :render_json_array_with_no_root, :check_default_root => true
|
||||
assert_equal '[]', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_empty_array
|
||||
get :render_json_empty_array
|
||||
assert_equal '{"test":[]}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_empty_array_checking_default_root
|
||||
get :render_json_empty_array, :check_default_root => true
|
||||
assert_equal '{"awesome":[]}', @response.body
|
||||
end
|
||||
|
||||
def test_render_json_empty_array_with_array_serializer_root_false
|
||||
ActiveModel::ArraySerializer.root = false
|
||||
get :render_json_empty_array
|
||||
assert_equal '[]', @response.body
|
||||
ensure # teardown
|
||||
ActiveModel::ArraySerializer.root = nil
|
||||
end
|
||||
|
||||
def test_render_json_array_with_custom_array_serializer
|
||||
get :render_json_array_with_custom_array_serializer
|
||||
assert_equal '{"items":[]}', @response.body
|
||||
end
|
||||
|
||||
end
|
||||
@ -1,51 +0,0 @@
|
||||
require "test_helper"
|
||||
|
||||
class RandomModel
|
||||
include ActiveModel::SerializerSupport
|
||||
end
|
||||
|
||||
class OtherRandomModel
|
||||
include ActiveModel::SerializerSupport
|
||||
end
|
||||
|
||||
class OtherRandomModelSerializer
|
||||
end
|
||||
|
||||
class RandomModelCollection
|
||||
include ActiveModel::ArraySerializerSupport
|
||||
end
|
||||
|
||||
module ActiveRecord
|
||||
class Relation
|
||||
end
|
||||
end
|
||||
|
||||
module Mongoid
|
||||
class Criteria
|
||||
end
|
||||
end
|
||||
|
||||
class SerializerSupportTest < ActiveModel::TestCase
|
||||
test "it returns nil if no serializer exists" do
|
||||
assert_equal nil, RandomModel.new.active_model_serializer
|
||||
end
|
||||
|
||||
test "it returns a deducted serializer if it exists exists" do
|
||||
assert_equal OtherRandomModelSerializer, OtherRandomModel.new.active_model_serializer
|
||||
end
|
||||
|
||||
test "it returns ArraySerializer for a collection" do
|
||||
assert_equal ActiveModel::ArraySerializer, RandomModelCollection.new.active_model_serializer
|
||||
end
|
||||
|
||||
test "it automatically includes array_serializer in active_record/relation" do
|
||||
ActiveSupport.run_load_hooks(:active_record)
|
||||
assert_equal ActiveModel::ArraySerializer, ActiveRecord::Relation.new.active_model_serializer
|
||||
end
|
||||
|
||||
test "it automatically includes array_serializer in mongoid/criteria" do
|
||||
ActiveSupport.run_load_hooks(:mongoid)
|
||||
assert_equal ActiveModel::ArraySerializer, Mongoid::Criteria.new.active_model_serializer
|
||||
end
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,218 +0,0 @@
|
||||
class BasicActiveModel
|
||||
include ActiveModel::Serializers::JSON
|
||||
def initialize(hash = {})
|
||||
@attributes = hash
|
||||
end
|
||||
|
||||
def serializable_hash(*)
|
||||
@attributes
|
||||
end
|
||||
|
||||
def method_missing(method)
|
||||
if @attributes.key? method
|
||||
@attributes[method]
|
||||
else
|
||||
raise NoMethodError
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class BasicSerializer < ActiveModel::Serializer
|
||||
attributes :name
|
||||
end
|
||||
|
||||
class Model
|
||||
def initialize(hash={})
|
||||
@attributes = hash
|
||||
end
|
||||
|
||||
def read_attribute_for_serialization(name)
|
||||
@attributes[name]
|
||||
end
|
||||
|
||||
def as_json(*)
|
||||
{ :model => "Model" }
|
||||
end
|
||||
end
|
||||
|
||||
class User
|
||||
include ActiveModel::SerializerSupport
|
||||
|
||||
attr_accessor :superuser
|
||||
|
||||
def initialize(hash={})
|
||||
@attributes = hash.merge(:first_name => "Jose", :last_name => "Valim", :password => "oh noes yugive my password")
|
||||
end
|
||||
|
||||
def read_attribute_for_serialization(name)
|
||||
@attributes[name]
|
||||
end
|
||||
|
||||
def super_user?
|
||||
@superuser
|
||||
end
|
||||
end
|
||||
|
||||
class Post < Model
|
||||
def initialize(attributes)
|
||||
super(attributes)
|
||||
self.comments ||= []
|
||||
self.comments_disabled = false
|
||||
self.author = nil
|
||||
end
|
||||
|
||||
attr_accessor :comments, :comments_disabled, :author
|
||||
def active_model_serializer; PostSerializer; end
|
||||
end
|
||||
|
||||
class Comment < Model
|
||||
def active_model_serializer; CommentSerializer; end
|
||||
end
|
||||
|
||||
class UserSerializer < ActiveModel::Serializer
|
||||
attributes :first_name, :last_name
|
||||
|
||||
def serializable_hash
|
||||
attributes.merge(:ok => true).merge(options[:scope])
|
||||
end
|
||||
end
|
||||
|
||||
class UserAttributesWithKeySerializer < ActiveModel::Serializer
|
||||
attributes :first_name => :f_name, :last_name => :l_name
|
||||
|
||||
def serializable_hash
|
||||
attributes.merge(:ok => true).merge(options[:scope])
|
||||
end
|
||||
end
|
||||
|
||||
class UserAttributesWithSomeKeySerializer < ActiveModel::Serializer
|
||||
attributes :first_name, :last_name => :l_name
|
||||
|
||||
def serializable_hash
|
||||
attributes.merge(:ok => true).merge(options[:scope])
|
||||
end
|
||||
end
|
||||
|
||||
class UserAttributesWithUnsymbolizableKeySerializer < ActiveModel::Serializer
|
||||
attributes :first_name, :last_name => :"last-name"
|
||||
|
||||
def serializable_hash
|
||||
attributes.merge(:ok => true).merge(options[:scope])
|
||||
end
|
||||
end
|
||||
|
||||
class DefaultUserSerializer < ActiveModel::Serializer
|
||||
attributes :first_name, :last_name
|
||||
end
|
||||
|
||||
class MyUserSerializer < ActiveModel::Serializer
|
||||
attributes :first_name, :last_name
|
||||
|
||||
def serializable_hash
|
||||
hash = attributes
|
||||
hash = hash.merge(:super_user => true) if object.super_user?
|
||||
hash
|
||||
end
|
||||
end
|
||||
|
||||
class CommentSerializer
|
||||
def initialize(comment, options={})
|
||||
@object = comment
|
||||
end
|
||||
|
||||
attr_reader :object
|
||||
|
||||
def serializable_hash
|
||||
{ :title => @object.read_attribute_for_serialization(:title) }
|
||||
end
|
||||
|
||||
def as_json(options=nil)
|
||||
options ||= {}
|
||||
if options[:root] == false
|
||||
serializable_hash
|
||||
else
|
||||
{ :comment => serializable_hash }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class PostSerializer < ActiveModel::Serializer
|
||||
attributes :title, :body
|
||||
has_many :comments, :serializer => CommentSerializer
|
||||
end
|
||||
|
||||
class PostWithConditionalCommentsSerializer < ActiveModel::Serializer
|
||||
root :post
|
||||
attributes :title, :body
|
||||
has_many :comments, :serializer => CommentSerializer
|
||||
|
||||
def include_associations!
|
||||
include! :comments unless object.comments_disabled
|
||||
end
|
||||
end
|
||||
|
||||
class PostWithMultipleConditionalsSerializer < ActiveModel::Serializer
|
||||
root :post
|
||||
attributes :title, :body, :author
|
||||
has_many :comments, :serializer => CommentSerializer
|
||||
|
||||
def include_comments?
|
||||
!object.comments_disabled
|
||||
end
|
||||
|
||||
def include_author?
|
||||
scope.super_user?
|
||||
end
|
||||
end
|
||||
|
||||
class Blog < Model
|
||||
attr_accessor :author
|
||||
end
|
||||
|
||||
class AuthorSerializer < ActiveModel::Serializer
|
||||
attributes :first_name, :last_name
|
||||
end
|
||||
|
||||
class BlogSerializer < ActiveModel::Serializer
|
||||
has_one :author, :serializer => AuthorSerializer
|
||||
end
|
||||
|
||||
class BlogWithRootSerializer < BlogSerializer
|
||||
root true
|
||||
end
|
||||
|
||||
class CustomPostSerializer < ActiveModel::Serializer
|
||||
attributes :title
|
||||
end
|
||||
|
||||
class CustomBlog < Blog
|
||||
attr_accessor :public_posts, :public_user
|
||||
end
|
||||
|
||||
class CustomBlogSerializer < ActiveModel::Serializer
|
||||
has_many :public_posts, :key => :posts, :serializer => PostSerializer
|
||||
has_one :public_user, :key => :user, :serializer => UserSerializer
|
||||
end
|
||||
|
||||
class SomeSerializer < ActiveModel::Serializer
|
||||
attributes :some
|
||||
end
|
||||
|
||||
class SomeObject < Struct.new(:some)
|
||||
include ActiveModel::Serializers::JSON
|
||||
end
|
||||
|
||||
# Set up some classes for polymorphic testing
|
||||
class Attachment < Model
|
||||
def attachable
|
||||
@attributes[:attachable]
|
||||
end
|
||||
|
||||
def readable
|
||||
@attributes[:readable]
|
||||
end
|
||||
|
||||
def edible
|
||||
@attributes[:edible]
|
||||
end
|
||||
end
|
||||
@ -1,55 +0,0 @@
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
|
||||
require 'rails'
|
||||
require 'action_controller'
|
||||
require 'action_controller/test_case'
|
||||
require 'action_controller/railtie'
|
||||
require 'active_support/json'
|
||||
|
||||
gem 'minitest'
|
||||
require 'minitest/autorun'
|
||||
if defined?(Minitest::Test)
|
||||
$minitest_version = 5 # rubocop:disable Style/GlobalVars
|
||||
# Minitest 5
|
||||
# https://github.com/seattlerb/minitest/blob/e21fdda9d/lib/minitest/autorun.rb
|
||||
# https://github.com/seattlerb/minitest/blob/e21fdda9d/lib/minitest.rb#L45-L59
|
||||
else
|
||||
$minitest_version = 4 # rubocop:disable Style/GlobalVars
|
||||
# Minitest 4
|
||||
# https://github.com/seattlerb/minitest/blob/644a52fd0/lib/minitest/autorun.rb
|
||||
# https://github.com/seattlerb/minitest/blob/644a52fd0/lib/minitest/unit.rb#L768-L787
|
||||
# Ensure backward compatibility with Minitest 4
|
||||
Minitest = MiniTest unless defined?(Minitest)
|
||||
Minitest::Test = MiniTest::Unit::TestCase
|
||||
def Minitest.after_run(&block)
|
||||
MiniTest::Unit.after_tests(&block)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
require "pry"
|
||||
|
||||
require "active_model_serializers"
|
||||
|
||||
module TestHelper
|
||||
Routes = ActionDispatch::Routing::RouteSet.new
|
||||
Routes.draw do
|
||||
resource :hypermedia
|
||||
get ':controller(/:action(/:id))'
|
||||
get ':controller(/:action)'
|
||||
end
|
||||
|
||||
ActionController::Base.send :include, Routes.url_helpers
|
||||
ActiveModel::Serializer.send :include, Routes.url_helpers
|
||||
end
|
||||
|
||||
ActiveSupport::TestCase.class_eval do
|
||||
setup do
|
||||
@routes = ::TestHelper::Routes
|
||||
end
|
||||
end
|
||||
|
||||
class Object
|
||||
undef_method :id if respond_to?(:id)
|
||||
end
|
||||
Loading…
Reference in New Issue
Block a user