Clear out master

This commit is contained in:
Benjamin Fleischer 2017-05-02 09:57:09 -05:00
parent dff621e174
commit 0ef6ac30fc
212 changed files with 666 additions and 21656 deletions

View File

@ -1,105 +0,0 @@
AllCops:
TargetRubyVersion: 2.1
Exclude:
- !ruby/regexp /(vendor|bundle|bin|db|tmp)\/.*/
DisplayCopNames: true
DisplayStyleGuide: true
# https://github.com/bbatsov/rubocop/blob/master/manual/caching.md
# https://github.com/bbatsov/rubocop/blob/e8680418b351491e111a18cf5b453fc07a3c5239/config/default.yml#L60-L77
UseCache: true
CacheRootDirectory: tmp
Rails:
Enabled: true
Lint/NestedMethodDefinition:
Enabled: false
Exclude:
- test/action_controller/serialization_test.rb
Style/Alias:
EnforcedStyle: prefer_alias
Style/StringLiterals:
EnforcedStyle: single_quotes
Metrics/AbcSize:
Max: 35 # TODO: Lower to 15
Metrics/ClassLength:
Max: 261 # TODO: Lower to 100
Exclude:
- test/**/*.rb
Metrics/CyclomaticComplexity:
Max: 7 # TODO: Lower to 6
Metrics/LineLength:
Max: 251 # TODO: Lower to 80
Metrics/MethodLength:
Max: 106 # TODO: Lower to 10
Metrics/PerceivedComplexity:
Max: 9 # TODO: Lower to 7
Style/AlignParameters:
EnforcedStyle: with_fixed_indentation
Style/ClassAndModuleChildren:
EnforcedStyle: nested
Style/Documentation:
Enabled: false
Style/MissingElse:
Enabled: true
EnforcedStyle: case
Style/EmptyElse:
EnforcedStyle: empty
Style/MultilineOperationIndentation:
EnforcedStyle: indented
Style/BlockDelimiters:
Enabled: true
EnforcedStyle: line_count_based
Style/SignalException:
EnforcedStyle: semantic
Style/TrailingCommaInLiteral:
EnforcedStyleForMultiline: no_comma
Style/ConditionalAssignment:
Enabled: false
Style/DotPosition:
EnforcedStyle: leading
########## test_helper.rb sanity
Style/EndBlock:
Exclude:
- test/test_helper.rb
Style/SpecialGlobalVars:
Exclude:
- test/test_helper.rb
Style/GlobalVars:
Exclude:
- test/test_helper.rb
Style/AndOr:
Exclude:
- test/test_helper.rb
- 'lib/active_model/serializer/lint.rb'
Style/Not:
Exclude:
- test/test_helper.rb
Style/ClassCheck:
Exclude:
- test/test_helper.rb

View File

@ -1,110 +0,0 @@
# https://github.com/colszowka/simplecov#using-simplecov-for-centralized-config
# see https://github.com/colszowka/simplecov/blob/master/lib/simplecov/defaults.rb
# vim: set ft=ruby
## DEFINE VARIABLES
@minimum_coverage = ENV.fetch('COVERAGE_MINIMUM') {
case (defined?(RUBY_ENGINE) && RUBY_ENGINE) || "ruby"
when 'jruby', 'rbx'
96.0
else
98.1
end
}.to_f.round(2)
# rubocop:disable Style/DoubleNegation
ENV['FULL_BUILD'] ||= ENV['CI']
@running_ci = !!(ENV['FULL_BUILD'] =~ /\Atrue\z/i)
@generate_report = @running_ci || !!(ENV['COVERAGE'] =~ /\Atrue\z/i)
@output = STDOUT
# rubocop:enable Style/DoubleNegation
## CONFIGURE SIMPLECOV
SimpleCov.profiles.define 'app' do
coverage_dir 'coverage'
load_profile 'test_frameworks'
add_group 'Libraries', 'lib'
add_group 'Long files' do |src_file|
src_file.lines.count > 100
end
class MaxLinesFilter < SimpleCov::Filter
def matches?(source_file)
source_file.lines.count < filter_argument
end
end
add_group 'Short files', MaxLinesFilter.new(5)
# Exclude these paths from analysis
add_filter '/config/'
add_filter '/db/'
add_filter 'tasks'
add_filter '/.bundle/'
end
## START TRACKING COVERAGE (before activating SimpleCov)
require 'coverage'
Coverage.start
## ADD SOME CUSTOM REPORTING AT EXIT
SimpleCov.at_exit do
next if $! and not ($!.kind_of? SystemExit and $!.success?)
header = "#{'*' * 20} SimpleCov Results #{'*' * 20}"
results = SimpleCov.result.format!.join("\n")
exit_message = <<-EOF
#{header}
{{RESULTS}}
{{FAILURE_MESSAGE}}
#{'*' * header.size}
EOF
percent = Float(SimpleCov.result.covered_percent)
if percent < @minimum_coverage
failure_message = <<-EOF
Spec coverage was not high enough: #{percent.round(2)}% is < #{@minimum_coverage}%
EOF
exit_message.sub!('{{RESULTS}}', results).sub!('{{FAILURE_MESSAGE}}', failure_message)
@output.puts exit_message
abort(failure_message) if @generate_report
elsif @running_ci
exit_message.sub!('{{RESULTS}}', results).sub!('{{FAILURE_MESSAGE}}', <<-EOF)
Nice job! Spec coverage (#{percent.round(2)}%) is still at or above #{@minimum_coverage}%
EOF
@output.puts exit_message
end
end
## CAPTURE CONFIG IN CLOSURE 'AppCoverage.start'
## to defer running until test/test_helper.rb is loaded.
# rubocop:disable Style/MultilineBlockChain
AppCoverage = Class.new do
def initialize(&block)
@block = block
end
def start
@block.call
end
end.new do
SimpleCov.start 'app'
if @generate_report
if @running_ci
require 'codeclimate-test-reporter'
@output.puts '[COVERAGE] Running with SimpleCov Simple Formatter and CodeClimate Test Reporter'
formatters = [
SimpleCov::Formatter::SimpleFormatter,
CodeClimate::TestReporter::Formatter
]
else
@output.puts '[COVERAGE] Running with SimpleCov HTML Formatter'
formatters = [SimpleCov::Formatter::HTMLFormatter]
end
else
formatters = []
end
SimpleCov.formatters = formatters
end
# rubocop:enable Style/MultilineBlockChain

View File

@ -2,54 +2,9 @@ language: ruby
sudo: false
rvm:
- 2.1
- 2.2.6
- 2.3.3
- ruby-head
- jruby-9.1.5.0 # is precompiled per http://rubies.travis-ci.org/
- jruby-head
jdk:
- oraclejdk8
before_install:
- gem update --system
- rvm @global do gem uninstall bundler -a -x
- rvm @global do gem install bundler -v 1.13.7
install: bundle install --path=vendor/bundle --retry=3 --jobs=3
cache:
directories:
- vendor/bundle
script:
- bundle exec rake ci
after_success:
- codeclimate-test-reporter
env:
global:
- "JRUBY_OPTS='--dev -J-Xmx1024M --debug'"
matrix:
- "RAILS_VERSION=4.1"
- "RAILS_VERSION=4.2"
- "RAILS_VERSION=5.0"
- "RAILS_VERSION=master"
matrix:
exclude:
- rvm: 2.1
env: RAILS_VERSION=master
- rvm: jruby-9.1.5.0
env: RAILS_VERSION=master
- rvm: jruby-head
env: RAILS_VERSION=master
- rvm: 2.1
env: RAILS_VERSION=5.0
- rvm: jruby-9.1.5.0
env: RAILS_VERSION=5.0
- rvm: jruby-head
env: RAILS_VERSION=5.0
allow_failures:
- rvm: ruby-head
- rvm: jruby-head
fast_finish: true
- true

92
CHANGELOG-0-08.md Normal file
View 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
View 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
View 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 unecessary 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
View 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)

View File

@ -1,6 +1,6 @@
## 0.10.x
## Dev
### [master (unreleased)](https://github.com/rails-api/active_model_serializers/compare/v0.10.6...master)
### [master (unreleased)](https://github.com/rails-api/active_model_serializers/compare/master..dev)
Breaking changes:
@ -10,641 +10,10 @@ Fixes:
Misc:
### [v0.10.6 (2017-05-01)](https://github.com/rails-api/active_model_serializers/compare/v0.10.5...v0.10.6)
## [0.10.x](CHANGELOG-0-10.md)
Fixes:
## [0.09.x](CHANGELOG-0-09.md)
- [#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)
## [0.08.x](CHANGELOG-0-08.md)
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 unecessary 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).
## 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)
## 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).
## 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)
## [Prehistory](CHANGELOG-prehistory.md)

View File

@ -4,13 +4,7 @@ Before opening an issue, try the following:
##### Consult the documentation
See if your issue can be resolved by information in the documentation.
- [0.10 (master) Documentation](https://github.com/rails-api/active_model_serializers/tree/master/docs)
- [![API Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/github/rails-api/active_model_serializers/v0.10.0)
- [Guides](docs)
- [0.9 (0-9-stable) Documentation](https://github.com/rails-api/active_model_serializers/tree/0-9-stable)
- [0.8 (0-8-stable) Documentation](https://github.com/rails-api/active_model_serializers/tree/0-8-stable)
See if your issue can be resolved by information in the [documentation](README.md).
##### Check for an existing issue
@ -43,7 +37,9 @@ for discussion or add your comments to existing ones.
We also gladly welcome pull requests. When preparing to work on pull request,
please adhere to these standards:
- Base work on the master branch unless fixing an issue with
- 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)
@ -52,10 +48,10 @@ please adhere to these standards:
- 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](https://github.com/rails-api/active_model_serializers/tree/master/docs)
- Include updates to the [documentation](docs)
where applicable.
- Update the
[CHANGELOG](https://github.com/rails-api/active_model_serializers/blob/master/CHANGELOG.md)
[CHANGELOG](CHANGELOG.md)
to the appropriate sections with a brief description of the changes.
- Do not change the VERSION file.
@ -102,4 +98,3 @@ fi
unset RAILS_VERSION
done
```

56
Gemfile
View File

@ -1,56 +0,0 @@
source 'https://rubygems.org'
#
# Add a Gemfile.local to locally bundle gems outside of version control
local_gemfile = File.join(File.expand_path('..', __FILE__), 'Gemfile.local')
eval_gemfile local_gemfile if File.readable?(local_gemfile)
# Specify your gem's dependencies in active_model_serializers.gemspec
gemspec
version = ENV['RAILS_VERSION'] || '4.2'
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])
group :bench do
# https://github.com/rails-api/active_model_serializers/commit/cb4459580a6f4f37f629bf3185a5224c8624ca76
gem 'benchmark-ips', '>= 2.7.2', require: false, group: :development
end
group :test do
gem 'sqlite3', platform: (@windows_platforms + [:ruby])
gem 'activerecord-jdbcsqlite3-adapter', platform: :jruby
gem 'codeclimate-test-reporter', require: false
gem 'm', '~> 1.5'
gem 'pry', '~> 0.10'
gem 'pry-byebug', '~> 3.4', platform: :ruby
end
group :development, :test do
gem 'rubocop', '~> 0.40.0', require: false
gem 'yard', require: false
end

268
README.md
View File

@ -1,77 +1,11 @@
# ActiveModelSerializers
<table>
<tr>
<td>Build Status</td>
<td>
<a href="https://travis-ci.org/rails-api/active_model_serializers"><img src="https://travis-ci.org/rails-api/active_model_serializers.svg?branch=master" alt="Build Status" ></a>
<a href="https://ci.appveyor.com/project/joaomdmoura/active-model-serializers/branch/master"><img src="https://ci.appveyor.com/api/projects/status/x6xdjydutm54gvyt/branch/master?svg=true" alt="Build status"></a>
</td>
</tr>
<tr>
<td>Code Quality</td>
<td>
<a href="https://codeclimate.com/github/rails-api/active_model_serializers"><img src="https://codeclimate.com/github/rails-api/active_model_serializers/badges/gpa.svg" alt="Code Quality"></a>
<a href="https://codebeat.co/projects/github-com-rails-api-active_model_serializers"><img src="https://codebeat.co/badges/a9ab35fa-8b5a-4680-9d4e-a81f9a55ebcd" alt="codebeat" ></a>
<a href="https://codeclimate.com/github/rails-api/active_model_serializers/coverage"><img src="https://codeclimate.com/github/rails-api/active_model_serializers/badges/coverage.svg" alt="Test Coverage"></a>
</td>
</tr>
<tr>
<td>Issue Stats</td>
<td>
<a href="https://github.com/rails-api/active_model_serializers/pulse/monthly">Pulse</a>
</td>
</tr>
</table>
## About
ActiveModelSerializers brings convention over configuration to your JSON generation.
ActiveModelSerializers works through two components: **serializers** and **adapters**.
Serializers describe _which_ attributes and relationships should be serialized.
Adapters describe _how_ attributes and relationships should be serialized.
SerializableResource co-ordinates the resource, Adapter and Serializer to produce the
resource serialization. The serialization has the `#as_json`, `#to_json` and `#serializable_hash`
methods used by the Rails JSON Renderer. (SerializableResource actually delegates
these methods to the adapter.)
By default ActiveModelSerializers will use the **Attributes Adapter** (no JSON root).
But we strongly advise you to use **JsonApi Adapter**, which
follows 1.0 of the format specified in [jsonapi.org/format](http://jsonapi.org/format).
Check how to change the adapter in the sections below.
`0.10.x` is **not** backward compatible with `0.9.x` nor `0.8.x`.
`0.10.x` is based on the `0.8.0` code, but with a more flexible
architecture. We'd love your help. [Learn how you can help here.](CONTRIBUTING.md)
It is generally safe and recommended to use the master branch.
## Installation
Add this line to your application's Gemfile:
```
gem 'active_model_serializers', '~> 0.10.0'
```
And then execute:
```
$ bundle
```
## Getting Started
See [Getting Started](docs/general/getting_started.md) for the nuts and bolts.
More information is available in the [Guides](docs) and
[High-level behavior](README.md#high-level-behavior).
## Getting Help
If you find a bug, please report an [Issue](https://github.com/rails-api/active_model_serializers/issues/new)
@ -86,10 +20,11 @@ Thanks!
## Documentation
If you're reading this at https://github.com/rails-api/active_model_serializers you are
reading documentation for our `master`, which may include features that have not
been released yet. Please see below for the documentation relevant to you.
reading documentation for our `master`, which is not yet released.
- [0.10 (master) Documentation](https://github.com/rails-api/active_model_serializers/tree/master)
Please see below for the documentation relevant to you.
- [0.10 (0-10-stable) Documentation](https://github.com/rails-api/active_model_serializers/tree/0-10-stable)
- [0.10.6 (latest release) Documentation](https://github.com/rails-api/active_model_serializers/tree/v0.10.6)
- [![API Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/gems/active_model_serializers/0.10.6)
- [Guides](docs)
@ -101,203 +36,8 @@ been released yet. Please see below for the documentation relevant to you.
## High-level behavior
Choose an adapter from [adapters](lib/active_model_serializers/adapter):
``` ruby
ActiveModelSerializers.config.adapter = :json_api # Default: `:attributes`
```
Given a [serializable model](lib/active_model/serializer/lint.rb):
```ruby
# either
class SomeResource < ActiveRecord::Base
# columns: title, body
end
# or
class SomeResource < ActiveModelSerializers::Model
attributes :title, :body
end
```
And initialized as:
```ruby
resource = SomeResource.new(title: 'ActiveModelSerializers', body: 'Convention over configuration')
```
Given a serializer for the serializable model:
```ruby
class SomeSerializer < ActiveModel::Serializer
attribute :title, key: :name
attributes :body
end
```
The model can be serialized as:
```ruby
options = {}
serialization = ActiveModelSerializers::SerializableResource.new(resource, options)
serialization.to_json
serialization.as_json
```
SerializableResource delegates to the adapter, which it builds as:
```ruby
adapter_options = {}
adapter = ActiveModelSerializers::Adapter.create(serializer, adapter_options)
adapter.to_json
adapter.as_json
adapter.serializable_hash
```
The adapter formats the serializer's attributes and associations (a.k.a. includes):
```ruby
serializer_options = {}
serializer = SomeSerializer.new(resource, serializer_options)
serializer.attributes
serializer.associations
```
## Architecture
This section focuses on architecture the 0.10.x version of ActiveModelSerializers. If you are interested in the architecture of the 0.8 or 0.9 versions,
please refer to the [0.8 README](https://github.com/rails-api/active_model_serializers/blob/0-8-stable/README.md) or
[0.9 README](https://github.com/rails-api/active_model_serializers/blob/0-9-stable/README.md).
The original design is also available [here](https://github.com/rails-api/active_model_serializers/blob/d72b66d4c5355b0ff0a75a04895fcc4ea5b0c65e/README.textile).
### ActiveModel::Serializer
An **`ActiveModel::Serializer`** wraps a [serializable resource](https://github.com/rails/rails/blob/4-2-stable/activemodel/lib/active_model/serialization.rb)
and exposes an `attributes` method, among a few others.
It allows you to specify which attributes and associations should be represented in the serializatation of the resource.
It requires an adapter to transform its attributes into a JSON document; it cannot be serialized itself.
It may be useful to think of it as a
[presenter](http://blog.steveklabnik.com/posts/2011-09-09-better-ruby-presenters).
#### ActiveModel::CollectionSerializer
The **`ActiveModel::CollectionSerializer`** represents a collection of resources as serializers
and, if there is no serializer, primitives.
### ActiveModelSerializers::Adapter::Base
The **`ActiveModelSerializeres::Adapter::Base`** describes the structure of the JSON document generated from a
serializer. For example, the `Attributes` example represents each serializer as its
unmodified attributes. The `JsonApi` adapter represents the serializer as a [JSON
API](http://jsonapi.org/) document.
### ActiveModelSerializers::SerializableResource
The **`ActiveModelSerializers::SerializableResource`** acts to coordinate the serializer(s) and adapter
to an object that responds to `to_json`, and `as_json`. It is used in the controller to
encapsulate the serialization resource when rendered. However, it can also be used on its own
to serialize a resource outside of a controller, as well.
### Primitive handling
Definitions: A primitive is usually a String or Array. There is no serializer
defined for them; they will be serialized when the resource is converted to JSON (`as_json` or
`to_json`). (The below also applies for any object with no serializer.)
- ActiveModelSerializers doesn't handle primitives passed to `render json:` at all.
Internally, if no serializer can be found in the controller, the resource is not decorated by
ActiveModelSerializers.
- However, when a primitive value is an attribute or in a collection, it is not modified.
When serializing a collection and the collection serializer (CollectionSerializer) cannot
identify a serializer for a resource in its collection, it throws [`:no_serializer`](https://github.com/rails-api/active_model_serializers/issues/1191#issuecomment-142327128).
For example, when caught by `Reflection#build_association`, and the association value is set directly:
```ruby
reflection_options[:virtual_value] = association_value.try(:as_json) || association_value
```
(which is called by the adapter as `serializer.associations(*)`.)
### How options are parsed
High-level overview:
- For a **collection**
- `:serializer` specifies the collection serializer and
- `:each_serializer` specifies the serializer for each resource in the collection.
- For a **single resource**, the `:serializer` option is the resource serializer.
- Options are partitioned in serializer options and adapter options. Keys for adapter options are specified by
[`ADAPTER_OPTION_KEYS`](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model_serializers/serializable_resource.rb#L5).
The remaining options are serializer options.
Details:
1. **ActionController::Serialization**
1. `serializable_resource = ActiveModelSerializers::SerializableResource.new(resource, options)`
1. `options` are partitioned into `adapter_opts` and everything else (`serializer_opts`).
The `adapter_opts` keys are defined in [`ActiveModelSerializers::SerializableResource::ADAPTER_OPTION_KEYS`](lib/active_model_serializers/serializable_resource.rb#L5).
1. **ActiveModelSerializers::SerializableResource**
1. `if serializable_resource.serializer?` (there is a serializer for the resource, and an adapter is used.)
- Where `serializer?` is `use_adapter? && !!(serializer)`
- Where `use_adapter?`: 'True when no explicit adapter given, or explicit value is truthy (non-nil);
False when explicit adapter is falsy (nil or false)'
- Where `serializer`:
1. from explicit `:serializer` option, else
2. implicitly from resource `ActiveModel::Serializer.serializer_for(resource)`
1. A side-effect of checking `serializer` is:
- The `:serializer` option is removed from the serializer_opts hash
- If the `:each_serializer` option is present, it is removed from the serializer_opts hash and set as the `:serializer` option
1. The serializer and adapter are created as
1. `serializer_instance = serializer.new(resource, serializer_opts)`
2. `adapter_instance = ActiveModel::Serializer::Adapter.create(serializer_instance, adapter_opts)`
1. **ActiveModel::Serializer::CollectionSerializer#new**
1. If the `serializer_instance` was a `CollectionSerializer` and the `:serializer` serializer_opts
is present, then [that serializer is passed into each resource](https://github.com/rails-api/active_model_serializers/blob/a54d237e2828fe6bab1ea5dfe6360d4ecc8214cd/lib/active_model/serializer/array_serializer.rb#L14-L16).
1. **ActiveModel::Serializer#attributes** is used by the adapter to get the attributes for
resource as defined by the serializer.
(In Rails, the `options` are also passed to the `as_json(options)` or `to_json(options)`
methods on the resource serialization by the Rails JSON renderer. They are, therefore, important
to know about, but not part of ActiveModelSerializers.)
### What does a 'serializable resource' look like?
- An `ActiveRecord::Base` object.
- Any Ruby object that passes the
[Lint](http://www.rubydoc.info/github/rails-api/active_model_serializers/ActiveModel/Serializer/Lint/Tests)
[code](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model/serializer/lint.rb).
ActiveModelSerializers provides a
[`ActiveModelSerializers::Model`](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model_serializers/model.rb),
which is a simple serializable PORO (Plain-Old Ruby Object).
`ActiveModelSerializers::Model` may be used either as a reference implementation, or in production code.
```ruby
class MyModel < ActiveModelSerializers::Model
attributes :id, :name, :level
end
```
The default serializer for `MyModel` would be `MyModelSerializer` whether MyModel is an
ActiveRecord::Base object or not.
Outside of the controller the rules are **exactly** the same as for records. For example:
```ruby
render json: MyModel.new(level: 'awesome'), adapter: :json
```
would be serialized the same as
```ruby
ActiveModelSerializers::SerializableResource.new(MyModel.new(level: 'awesome'), adapter: :json).as_json
```
## Semantic Versioning
This project adheres to [semver](http://semver.org/)

View File

@ -3,72 +3,3 @@ begin
rescue LoadError
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
end
begin
require 'simplecov'
rescue LoadError # rubocop:disable Lint/HandleExceptions
end
import('lib/tasks/rubocop.rake')
Bundler::GemHelper.install_tasks
require 'yard'
namespace :yard do
YARD::Rake::YardocTask.new(:doc) do |t|
t.stats_options = ['--list-undoc']
end
desc 'start a gem server'
task :server do
sh 'bundle exec yard server --gems'
end
desc 'use Graphviz to generate dot graph'
task :graph do
output_file = 'doc/erd.dot'
sh "bundle exec yard graph --protected --full --dependencies > #{output_file}"
puts 'open doc/erd.dot if you have graphviz installed'
end
end
require 'rake/testtask'
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.ruby_opts << ' -w' unless ENV['NO_WARN'] == 'true'
t.verbose = true
end
desc 'Run isolated tests'
task isolated: ['test:isolated']
namespace :test do
task :isolated do
desc 'Run isolated tests for Railtie'
require 'shellwords'
dir = File.dirname(__FILE__)
dir = Shellwords.shellescape(dir)
isolated_test_files = FileList['test/**/*_test_isolated.rb']
# https://github.com/rails/rails/blob/3d590add45/railties/lib/rails/generators/app_base.rb#L345-L363
_bundle_command = Gem.bin_path('bundler', 'bundle')
require 'bundler'
Bundler.with_clean_env do
isolated_test_files.all? do |test_file|
command = "-w -I#{dir}/lib -I#{dir}/test #{Shellwords.shellescape(test_file)}"
full_command = %("#{Gem.ruby}" #{command})
system(full_command)
end or fail 'Failures' # rubocop:disable Style/AndOr
end
end
end
if ENV['RAILS_VERSION'].to_s > '4.0' && RUBY_ENGINE == 'ruby'
task default: [:isolated, :test, :rubocop]
else
task default: [:test, :rubocop]
end
desc 'CI test task'
task ci: [:default]

View File

@ -1,11 +1,8 @@
# coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'active_model/serializer/version'
Gem::Specification.new do |spec|
spec.name = 'active_model_serializers'
spec.version = ActiveModel::Serializer::VERSION
spec.version = "1.0.0-dev"
spec.platform = Gem::Platform::RUBY
spec.authors = ['Steve Klabnik']
spec.email = ['steve@steveklabnik.com']
@ -20,44 +17,4 @@ Gem::Specification.new do |spec|
spec.executables = []
spec.required_ruby_version = '>= 2.1'
rails_versions = ['>= 4.1', '< 6']
spec.add_runtime_dependency 'activemodel', rails_versions
# 'activesupport', rails_versions
# 'builder'
spec.add_runtime_dependency 'actionpack', rails_versions
# 'activesupport', rails_versions
# 'rack'
# 'rack-test', '~> 0.6.2'
spec.add_development_dependency 'railties', rails_versions
# 'activesupport', rails_versions
# 'actionpack', rails_versions
# 'rake', '>= 0.8.7'
# 'activesupport', rails_versions
# 'i18n,
# 'tzinfo'
# 'minitest'
# 'thread_safe'
spec.add_runtime_dependency 'jsonapi-renderer', ['>= 0.1.1.beta1', '< 0.2']
spec.add_runtime_dependency 'case_transform', '>= 0.2'
spec.add_development_dependency 'activerecord', rails_versions
# arel
# activesupport
# activemodel
# Soft dependency for pagination
spec.add_development_dependency 'kaminari', ' ~> 0.16.3'
spec.add_development_dependency 'will_paginate', '~> 3.0', '>= 3.0.7'
spec.add_development_dependency 'bundler', '~> 1.6'
spec.add_development_dependency 'simplecov', '~> 0.11'
spec.add_development_dependency 'timecop', '~> 0.7'
spec.add_development_dependency 'grape', ['>= 0.13', '< 0.19.1']
spec.add_development_dependency 'json_schema'
spec.add_development_dependency 'rake', ['>= 10.0', '< 12.0']
end

View File

@ -2,29 +2,10 @@ version: 1.0.{build}-{branch}
skip_tags: true
environment:
JRUBY_OPTS: "--dev -J-Xmx1024M --debug"
matrix:
- ruby_version: "Ruby21"
- ruby_version: "Ruby21-x64"
cache:
- vendor/bundle
install:
- SET PATH=C:\%ruby_version%\bin;%PATH%
- gem update --system
- gem uninstall bundler -a -x
- gem install bundler -v 1.13.7
- bundle env
- bundle install --path=vendor/bundle --retry=3 --jobs=3
before_test:
- ruby -v
- gem -v
- bundle -v
test_script:
- bundle exec rake ci
- true
build: off

171
bin/bench
View File

@ -1,171 +0,0 @@
#!/usr/bin/env ruby
# ActiveModelSerializers Benchmark driver
# Adapted from
# https://github.com/ruby-bench/ruby-bench-suite/blob/8ad567f7e43a044ae48c36833218423bb1e2bd9d/rails/benchmarks/driver.rb
require 'bundler'
Bundler.setup
require 'json'
require 'pathname'
require 'optparse'
require 'digest'
require 'pathname'
require 'shellwords'
require 'logger'
require 'English'
class BenchmarkDriver
ROOT = Pathname File.expand_path(File.join('..', '..'), __FILE__)
BASE = ENV.fetch('BASE') { ROOT.join('test', 'benchmark') }
ESCAPED_BASE = Shellwords.shellescape(BASE)
def self.benchmark(options)
new(options).run
end
def self.parse_argv_and_run(argv = ARGV, options = {})
options = {
repeat_count: 1,
pattern: [],
env: 'CACHE_ON=on'
}.merge!(options)
OptionParser.new do |opts|
opts.banner = 'Usage: bin/bench [options]'
opts.on('-r', '--repeat-count [NUM]', 'Run benchmarks [NUM] times taking the best result') do |value|
options[:repeat_count] = value.to_i
end
opts.on('-p', '--pattern <PATTERN1,PATTERN2,PATTERN3>', 'Benchmark name pattern') do |value|
options[:pattern] = value.split(',')
end
opts.on('-e', '--env <var1=val1,var2=val2,var3=vale>', 'ENV variables to pass in') do |value|
options[:env] = value.split(',')
end
end.parse!(argv)
benchmark(options)
end
attr_reader :commit_hash, :base
# Based on logfmt:
# https://www.brandur.org/logfmt
# For more complete implementation see:
# see https://github.com/arachnid-cb/logfmtr/blob/master/lib/logfmtr/base.rb
# For usage see:
# https://blog.codeship.com/logfmt-a-log-format-thats-easy-to-read-and-write/
# https://engineering.heroku.com/blogs/2014-09-05-hutils-explore-your-structured-data-logs/
# For Ruby parser see:
# https://github.com/cyberdelia/logfmt-ruby
def self.summary_logger(device = 'output.txt')
require 'time'
logger = Logger.new(device)
logger.level = Logger::INFO
logger.formatter = proc { |severity, datetime, progname, msg|
msg = "'#{msg}'"
"level=#{severity} time=#{datetime.utc.iso8601(6)} pid=#{Process.pid} progname=#{progname} msg=#{msg}#{$INPUT_RECORD_SEPARATOR}"
}
logger
end
def self.stdout_logger
logger = Logger.new(STDOUT)
logger.level = Logger::INFO
logger.formatter = proc { |_, _, _, msg| "#{msg}#{$INPUT_RECORD_SEPARATOR}" }
logger
end
def initialize(options)
@writer = ENV['SUMMARIZE'] ? self.class.summary_logger : self.class.stdout_logger
@repeat_count = options[:repeat_count]
@pattern = options[:pattern]
@commit_hash = options.fetch(:commit_hash) { `git rev-parse --short HEAD`.chomp }
@base = options.fetch(:base) { ESCAPED_BASE }
@env = Array(options[:env]).join(' ')
@rubyopt = options[:rubyopt] # TODO: rename
end
def run
files.each do |path|
next if !@pattern.empty? && /#{@pattern.join('|')}/ !~ File.basename(path)
run_single(Shellwords.shellescape(path))
end
end
private
def files
Dir[File.join(base, 'bm_*')]
end
def run_single(path)
script = "RAILS_ENV=production #{@env} ruby #{@rubyopt} #{path}"
environment = `ruby -v`.chomp.strip[/\d+\.\d+\.\d+\w+/]
runs_output = measure(script)
if runs_output.empty?
results = { error: :no_results }
return
end
results = {}
results['commit_hash'] = commit_hash
results['version'] = runs_output.first['version']
results['rails_version'] = runs_output.first['rails_version']
results['benchmark_run[environment]'] = environment
results['runs'] = []
runs_output.each do |output|
results['runs'] << {
'benchmark_type[category]' => output['label'],
'benchmark_run[result][iterations_per_second]' => output['iterations_per_second'].round(3),
'benchmark_run[result][total_allocated_objects_per_iteration]' => output['total_allocated_objects_per_iteration']
}
end
ensure
results && report(results)
end
def report(results)
@writer.info { 'Benchmark results:' }
@writer.info { JSON.pretty_generate(results) }
end
def summarize(result)
puts "#{result['label']} #{result['iterations_per_second']}/ips; #{result['total_allocated_objects_per_iteration']} objects"
end
# FIXME: ` provides the full output but it'll return failed output as well.
def measure(script)
results = Hash.new { |h, k| h[k] = [] }
@repeat_count.times do
output = sh(script)
output.each_line do |line|
next if line.nil?
begin
result = JSON.parse(line)
rescue JSON::ParserError
result = { error: line } # rubocop:disable Lint/UselessAssignment
else
summarize(result)
results[result['label']] << result
end
end
end
results.map do |_, bm_runs|
bm_runs.sort_by do |run|
run['iterations_per_second']
end.last
end
end
def sh(cmd)
`#{cmd}`
end
end
BenchmarkDriver.parse_argv_and_run if $PROGRAM_NAME == __FILE__

View File

@ -1,316 +0,0 @@
#!/usr/bin/env ruby
require 'fileutils'
require 'pathname'
require 'shellwords'
require 'English'
############################
# USAGE
#
# bundle exec bin/bench_regression <ref1> <ref2>
# <ref1> defaults to the current branch
# <ref2> defaults to the master branch
# bundle exec bin/bench_regression current # will run on the current branch
# bundle exec bin/bench_regression revisions 792fb8a90 master # every revision inclusive
# bundle exec bin/bench_regression 792fb8a90 master --repeat-count 2 --env CACHE_ON=off
# bundle exec bin/bench_regression vendor
###########################
class BenchRegression
ROOT = Pathname File.expand_path(File.join(*['..', '..']), __FILE__)
TMP_DIR_NAME = File.join('tmp', 'bench')
TMP_DIR = File.join(ROOT, TMP_DIR_NAME)
E_TMP_DIR = Shellwords.shellescape(TMP_DIR)
load ROOT.join('bin', 'bench')
attr_reader :source_stasher
def initialize
@source_stasher = SourceStasher.new
end
class SourceStasher
attr_reader :gem_require_paths, :gem_paths
attr_writer :vendor
def initialize
@gem_require_paths = []
@gem_paths = []
refresh_temp_dir
@vendor = false
end
def temp_dir_empty?
File.directory?(TMP_DIR) &&
Dir[File.join(TMP_DIR, '*')].none?
end
def empty_temp_dir
return if @vendor
return if temp_dir_empty?
FileUtils.mkdir_p(TMP_DIR)
Dir[File.join(TMP_DIR, '*')].each do |file|
if File.directory?(file)
FileUtils.rm_rf(file)
else
FileUtils.rm(file)
end
end
end
def fill_temp_dir
vendor_files(Dir[File.join(ROOT, 'test', 'benchmark', '*.{rb,ru}')])
# vendor_file(File.join('bin', 'bench'))
housekeeping { empty_temp_dir }
vendor_gem('benchmark-ips')
end
def vendor_files(files)
files.each do |file|
vendor_file(file)
end
end
def vendor_file(file)
FileUtils.cp(file, File.join(TMP_DIR, File.basename(file)))
end
def vendor_gem(gem_name)
directory_name = `bundle exec gem unpack benchmark-ips --target=#{E_TMP_DIR}`[/benchmark-ips.+\d/]
gem_paths << File.join(TMP_DIR, directory_name)
gem_require_paths << File.join(TMP_DIR_NAME, directory_name, 'lib')
housekeeping { remove_vendored_gems }
end
def remove_vendored_gems
return if @vendor
FileUtils.rm_rf(*gem_paths)
end
def refresh_temp_dir
empty_temp_dir
fill_temp_dir
end
def housekeeping
at_exit { yield }
end
end
module RevisionMethods
module_function
def current_branch
@current_branch ||= `cat .git/HEAD | cut -d/ -f3,4,5`.chomp
end
def current_revision
`git rev-parse --short HEAD`.chomp
end
def revision_description(rev)
`git log --oneline -1 #{rev}`.chomp
end
def revisions(start_ref, end_ref)
cmd = "git rev-list --reverse #{start_ref}..#{end_ref}"
`#{cmd}`.chomp.split("\n")
end
def checkout_ref(ref)
`git checkout #{ref}`.chomp
if $CHILD_STATUS
STDERR.puts "Checkout failed: #{ref}, #{$CHILD_STATUS.exitstatus}" unless $CHILD_STATUS.success?
$CHILD_STATUS.success?
else
true
end
end
def clean_head
system('git reset --hard --quiet')
end
end
module ShellMethods
def sh(cmd)
puts cmd
# system(cmd)
run(cmd)
# env = {}
# # out = STDOUT
# pid = spawn(env, cmd)
# Process.wait(pid)
# pid = fork do
# exec cmd
# end
# Process.waitpid2(pid)
# puts $CHILD_STATUS.exitstatus
end
require 'pty'
# should consider trapping SIGINT in here
def run(cmd)
puts cmd
child_process = ''
result = ''
# http://stackoverflow.com/a/1162850
# stream output of subprocess
begin
PTY.spawn(cmd) do |stdin, _stdout, pid|
begin
# Do stuff with the output here. Just printing to show it works
stdin.each do |line|
print line
result << line
end
child_process = PTY.check(pid)
rescue Errno::EIO
puts 'Errno:EIO error, but this probably just means ' \
'that the process has finished giving output'
end
end
rescue PTY::ChildExited
puts 'The child process exited!'
end
unless (child_process && child_process.success?)
exitstatus = child_process.exitstatus
puts "FAILED: #{child_process.pid} exited with status #{exitstatus.inspect} due to failed command #{cmd}"
exit exitstatus || 1
end
result
end
def bundle(ref)
system("rm -f Gemfile.lock")
# This is absolutely critical for bundling to work
Bundler.with_clean_env do
system("bundle check ||
bundle install --local ||
bundle install ||
bundle update")
end
# if $CHILD_STATUS
# STDERR.puts "Bundle failed at: #{ref}, #{$CHILD_STATUS.exitstatus}" unless $CHILD_STATUS.success?
# $CHILD_STATUS.success?
# else
# false
# end
end
end
include ShellMethods
include RevisionMethods
def benchmark_refs(ref1: nil, ref2: nil, cmd:)
checking_out = false
ref0 = current_branch
ref1 ||= current_branch
ref2 ||= 'master'
p [ref0, ref1, ref2, current_revision]
run_benchmark_at_ref(cmd, ref1)
p [ref0, ref1, ref2, current_revision]
run_benchmark_at_ref(cmd, ref2)
p [ref0, ref1, ref2, current_revision]
checking_out = true
checkout_ref(ref0)
rescue Exception # rubocop:disable Lint/RescueException
STDERR.puts "[ERROR] #{$!.message}"
checkout_ref(ref0) unless checking_out
raise
end
def benchmark_revisions(ref1: nil, ref2: nil, cmd:)
checking_out = false
ref0 = current_branch
ref1 ||= current_branch
ref2 ||= 'master'
revisions(ref1, ref2).each do |rev|
STDERR.puts "Checking out: #{revision_description(rev)}"
run_benchmark_at_ref(cmd, rev)
clean_head
end
checking_out = true
checkout_ref(ref0)
rescue Exception # rubocop:disable Lint/RescueException
STDERR.puts "[ERROR]: #{$!.message}"
checkout_ref(ref0) unless checking_out
raise
end
def run_benchmark_at_ref(cmd, ref)
checkout_ref(ref)
run_benchmark(cmd, ref)
end
def run_benchmark(cmd, ref = nil)
ref ||= current_revision
bundle(ref) &&
benchmark_tests(cmd, ref)
end
def benchmark_tests(cmd, ref)
base = E_TMP_DIR
# cmd.sub('bin/bench', 'tmp/revision_runner/bench')
# bundle = Gem.bin('bunle'
# Bundler.with_clean_env(&block)
# cmd = Shellwords.shelljoin(cmd)
# cmd = "COMMIT_HASH=#{ref} BASE=#{base} bundle exec ruby -rbenchmark/ips #{cmd}"
# Add vendoring benchmark/ips to load path
# CURRENT THINKING: IMPORTANT
# Pass into require statement as RUBYOPTS i.e. via env rather than command line argument
# otherwise, have a 'fast ams benchmarking' module that extends benchmarkings to add the 'ams'
# method but doesn't depend on benchmark-ips
options = {
commit_hash: ref,
base: base,
rubyopt: Shellwords.shellescape("-Ilib:#{source_stasher.gem_require_paths.join(':')}")
}
BenchmarkDriver.parse_argv_and_run(ARGV.dup, options)
end
end
if $PROGRAM_NAME == __FILE__
benchmarking = BenchRegression.new
case ARGV[0]
when 'current'
# Run current branch only
# super simple command line parsing
args = ARGV.dup
_ = args.shift # remove 'current' from args
cmd = args
benchmarking.run_benchmark(cmd)
when 'revisions'
# Runs on every revision
# super simple command line parsing
args = ARGV.dup
_ = args.shift
ref1 = args.shift # remove 'revisions' from args
ref2 = args.shift
cmd = args
benchmarking.benchmark_revisions(ref1: ref1, ref2: ref2, cmd: cmd)
when 'vendor'
# Just prevents vendored files from being cleaned up
# at exit. (They are vendored at initialize.)
benchmarking.source_stasher.vendor = true
else
# Default: Compare current_branch to master
# Optionally: pass in two refs as args to `bin/bench_regression`
# TODO: Consider checking across more revisions, to automatically find problems.
# super simple command line parsing
args = ARGV.dup
ref1 = args.shift
ref2 = args.shift
cmd = args
benchmarking.benchmark_refs(ref1: ref1, ref2: ref2, cmd: cmd)
end
end

View File

@ -1,38 +0,0 @@
#!/usr/bin/env bash
#
# Usage:
# bin/rubocop [-A|-t|-h]
# bin/rubocop [file or path] [cli options]
#
# Options:
# Autocorrect -A
# AutoGenConfig -t
# Usage -h,--help,help
set -e
case $1 in
-A)
echo "Rubocop autocorrect is ON" >&2
bundle exec rake -f lib/tasks/rubocop.rake rubocop:auto_correct
;;
-t)
echo "Rubocop is generating a new TODO" >&2
bundle exec rake -f lib/tasks/rubocop.rake rubocop:auto_gen_config
;;
-h|--help|help)
sed -ne '/^#/!q;s/.\{1,2\}//;1d;p' < "$0"
;;
*)
# with no args, run vanilla rubocop
# else assume we're passing in arbitrary arguments
if [ -z "$1" ]; then
bundle exec rake -f lib/tasks/rubocop.rake rubocop
else
bundle exec rubocop "$@"
fi
;;
esac

View File

@ -1,39 +0,0 @@
#!/usr/bin/env bash
set -e
case "$1" in
start)
config="${CONFIG_RU:-test/benchmark/config.ru}"
bundle exec ruby -Ilib -S rackup "$config" --daemonize --pid tmp/benchmark_app.pid --warn --server webrick
until [ -f 'tmp/benchmark_app.pid' ]; do
sleep 0.1 # give it time to start.. I don't know a better way
done
cat tmp/benchmark_app.pid
true
;;
stop)
if [ -f 'tmp/benchmark_app.pid' ]; then
kill -TERM $(cat tmp/benchmark_app.pid)
else
echo 'No pidfile'
false
fi
;;
status)
if [ -f 'tmp/benchmark_app.pid' ]; then
kill -0 $(cat tmp/benchmark_app.pid)
[ "$?" -eq 0 ]
else
echo 'No pidfile'
false
fi
;;
*)
echo "Usage: $0 [start|stop|status]"
;;
esac

View File

@ -1,41 +0,0 @@
# Docs - ActiveModel::Serializer 0.10.x
This is the documentation of ActiveModelSerializers, it's focused on the **0.10.x version.**
-----
## General
- [Getting Started](general/getting_started.md)
- [Configuration Options](general/configuration_options.md)
- [Serializers](general/serializers.md)
- [Adapters](general/adapters.md)
- [Rendering](general/rendering.md)
- [Caching](general/caching.md)
- [Logging](general/logging.md)
- [Deserialization](general/deserialization.md)
- [Instrumentation](general/instrumentation.md)
- JSON API
- [Schema](jsonapi/schema.md)
- [Errors](jsonapi/errors.md)
## How to
- [How to add root key](howto/add_root_key.md)
- [How to add pagination links](howto/add_pagination_links.md)
- [How to add relationship links](howto/add_relationship_links.md)
- [Using ActiveModelSerializers Outside Of Controllers](howto/outside_controller_use.md)
- [Testing ActiveModelSerializers](howto/test.md)
- [Passing Arbitrary Options](howto/passing_arbitrary_options.md)
- [How to serialize a Plain-Old Ruby Object (PORO)](howto/serialize_poro.md)
- [How to upgrade from `0.8` to `0.10` safely](howto/upgrade_from_0_8_to_0_10.md)
## Integrations
| Integration | Supported ActiveModelSerializers versions | Gem name and/or link
|----|-----|----
| Ember.js | 0.9.x | [active-model-adapter](https://github.com/ember-data/active-model-adapter)
| Ember.js | 0.10.x + | [docs/integrations/ember-and-json-api.md](integrations/ember-and-json-api.md)
| Grape | 0.10.x + | [docs/integrations/grape.md](integrations/grape.md) |
| Grape | 0.9.x | https://github.com/jrhe/grape-active_model_serializers/ |
| Sinatra | 0.9.x | https://github.com/SauloSilva/sinatra-active-model-serializers/

View File

@ -1,58 +0,0 @@
# STYLE
## Code and comments
- We are actively working to identify tasks under the label [**Good for New
Contributors**](https://github.com/rails-api/active_model_serializers/labels/Good%20for%20New%20Contributors).
- [Changelog
Missing](https://github.com/rails-api/active_model_serializers/issues?q=label%3A%22Changelog+Missing%22+is%3Aclosed) is
an easy way to help out.
- [Fix a bug](https://github.com/rails-api/active_model_serializers/labels/Ready%20for%20PR).
- Ready for PR - A well defined bug, needs someone to PR a fix.
- Bug - Anything that is broken.
- Regression - A bug that did not exist in previous versions and isn't a new feature (applied in tandem with Bug).
- Performance - A performance related issue. We could track this as a bug, but usually these would have slightly lower priority than standard bugs.
- [Develop new features](https://github.com/rails-api/active_model_serializers/labels/Feature).
- [Improve code quality](https://codeclimate.com/github/rails-api/active_model_serializers/code?sort=smell_count&sort_direction=desc).
- [Improve amount of code exercised by tests](https://codeclimate.com/github/rails-api/active_model_serializers/coverage?sort=covered_percent&sort_direction=asc).
- [Fix RuboCop (Style) TODOS](https://github.com/rails-api/active_model_serializers/blob/master/.rubocop_todo.yml).
- Delete and offsense, run `rake rubocop` (or possibly `rake rubocop:auto_correct`),
and [submit a PR](CONTRIBUTING.md#submitting-a-pull-request-pr).
- We are also encouraging comments to substantial changes (larger than bugfixes and simple features) under an
"RFC" (Request for Comments) process before we start active development.
Look for the [**RFC**](https://github.com/rails-api/active_model_serializers/labels/RFC) label.
## Pull requests
- If the tests pass and the pull request looks good, a maintainer will merge it.
- If the pull request needs to be changed,
- you can change it by updating the branch you generated the pull request from
- either by adding more commits, or
- by force pushing to it
- A maintainer can make any changes themselves and manually merge the code in.
## Commit messages
- [A Note About Git Commit Messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
- [http://stopwritingramblingcommitmessages.com/](http://stopwritingramblingcommitmessages.com/)
- [ThoughtBot style guide](https://github.com/thoughtbot/guides/tree/master/style#git)
#### About Pull Requests (PR's)
- [Using Pull Requests](https://help.github.com/articles/using-pull-requests)
- [Github pull requests made easy](http://www.element84.com/github-pull-requests-made-easy.html)
- [Exercism Git Workflow](http://help.exercism.io/git-workflow.html).
- [Level up your Git](http://rakeroutes.com/blog/deliberate-git/)
- [All Your Open Source Code Are Belong To Us](http://www.benjaminfleischer.com/2013/07/30/all-your-open-source-code-are-belong-to-us/)
## Issue Labeling
ActiveModelSerializers uses a subset of [StandardIssueLabels](https://github.com/wagenet/StandardIssueLabels) for Github Issues. You can [see our labels here](https://github.com/rails-api/active_model_serializers/labels).

View File

@ -1,263 +0,0 @@
[Back to Guides](../README.md)
# Adapters
ActiveModelSerializers offers the ability to configure which adapter
to use both globally and/or when serializing (usually when rendering).
The global adapter configuration is set on [`ActiveModelSerializers.config`](configuration_options.md).
It should be set only once, preferably at initialization.
For example:
```ruby
ActiveModelSerializers.config.adapter = ActiveModelSerializers::Adapter::JsonApi
```
or
```ruby
ActiveModelSerializers.config.adapter = :json_api
```
or
```ruby
ActiveModelSerializers.config.adapter = :json
```
The local adapter option is in the format `adapter: adapter`, where `adapter` is
any of the same values as set globally.
The configured adapter can be set as a symbol, class, or class name, as described in
[Advanced adapter configuration](adapters.md#advanced-adapter-configuration).
The `Attributes` adapter does not include a root key. It is just the serialized attributes.
Use either the `JSON` or `JSON API` adapters if you want the response document to have a root key.
## Built in Adapters
### Attributes - Default
It's the default adapter, it generates a json response without a root key.
Doesn't follow any specific convention.
##### Example output
```json
{
"title": "Title 1",
"body": "Body 1",
"publish_at": "2020-03-16T03:55:25.291Z",
"author": {
"first_name": "Bob",
"last_name": "Jones"
},
"comments": [
{
"body": "cool"
},
{
"body": "awesome"
}
]
}
```
### JSON
The json response is always rendered with a root key.
The root key can be overridden by:
* passing the `root` option in the render call. See details in the [Rendering Guides](rendering.md#overriding-the-root-key).
* setting the `type` of the serializer. See details in the [Serializers Guide](serializers.md#type).
Doesn't follow any specific convention.
##### Example output
```json
{
"post": {
"title": "Title 1",
"body": "Body 1",
"publish_at": "2020-03-16T03:55:25.291Z",
"author": {
"first_name": "Bob",
"last_name": "Jones"
},
"comments": [{
"body": "cool"
}, {
"body": "awesome"
}]
}
}
```
### JSON API
This adapter follows **version 1.0** of the [format specified](../jsonapi/schema.md) in
[jsonapi.org/format](http://jsonapi.org/format).
##### Example output
```json
{
"data": {
"id": "1337",
"type": "posts",
"attributes": {
"title": "Title 1",
"body": "Body 1",
"publish-at": "2020-03-16T03:55:25.291Z"
},
"relationships": {
"author": {
"data": {
"id": "1",
"type": "authors"
}
},
"comments": {
"data": [{
"id": "7",
"type": "comments"
}, {
"id": "12",
"type": "comments"
}]
}
},
"links": {
"post-authors": "https://example.com/post_authors"
},
"meta": {
"rating": 5,
"favorite-count": 10
}
}
}
```
### Include option
Which [serializer associations](https://github.com/rails-api/active_model_serializers/blob/master/docs/general/serializers.md#associations) are rendered can be specified using the `include` option. The option usage is consistent with [the include option in the JSON API spec](http://jsonapi.org/format/#fetching-includes), and is available in all adapters.
Example of the usage:
```ruby
render json: @posts, include: ['author', 'comments', 'comments.author']
# or
render json: @posts, include: 'author,comments,comments.author'
```
The format of the `include` option can be either:
- a String composed of a comma-separated list of [relationship paths](http://jsonapi.org/format/#fetching-includes).
- an Array of Symbols and Hashes.
- a mix of both.
An empty string or an empty array will prevent rendering of any associations.
In addition, two types of wildcards may be used:
- `*` includes one level of associations.
- `**` includes all recursively.
These can be combined with other paths.
```ruby
render json: @posts, include: '**' # or '*' for a single layer
```
The following would render posts and include:
- the author
- the author's comments, and
- every resource referenced by the author's comments (recursively).
It could be combined, like above, with other paths in any combination desired.
```ruby
render json: @posts, include: 'author.comments.**'
```
**Note:** Wildcards are ActiveModelSerializers-specific, they are not part of the JSON API spec.
The default include for the JSON API adapter is no associations. The default for the JSON and Attributes adapters is all associations.
For the JSON API adapter associated resources will be gathered in the `"included"` member. For the JSON and Attributes
adapters associated resources will be rendered among the other attributes.
Only for the JSON API adapter you can specify, which attributes of associated resources will be rendered. This feature
is called [sparse fieldset](http://jsonapi.org/format/#fetching-sparse-fieldsets):
```ruby
render json: @posts, include: 'comments', fields: { comments: ['content', 'created_at'] }
```
##### Security Considerations
Since the included options may come from the query params (i.e. user-controller):
```ruby
render json: @posts, include: params[:include]
```
The user could pass in `include=**`.
We recommend filtering any user-supplied includes appropriately.
## Advanced adapter configuration
### Registering an adapter
The default adapter can be configured, as above, to use any class given to it.
An adapter may also be specified, e.g. when rendering, as a class or as a symbol.
If a symbol, then the adapter must be, e.g. `:great_example`,
`ActiveModelSerializers::Adapter::GreatExample`, or registered.
There are two ways to register an adapter:
1) The simplest, is to subclass `ActiveModelSerializers::Adapter::Base`, e.g. the below will
register the `Example::UsefulAdapter` as `"example/useful_adapter"`.
```ruby
module Example
class UsefulAdapter < ActiveModelSerializers::Adapter::Base
end
end
```
You'll notice that the name it registers is the underscored namespace and class.
Under the covers, when the `ActiveModelSerializers::Adapter::Base` is subclassed, it registers
the subclass as `register("example/useful_adapter", Example::UsefulAdapter)`
2) Any class can be registered as an adapter by calling `register` directly on the
`ActiveModelSerializers::Adapter` class. e.g., the below registers `MyAdapter` as
`:special_adapter`.
```ruby
class MyAdapter; end
ActiveModelSerializers::Adapter.register(:special_adapter, MyAdapter)
```
### Looking up an adapter
| Method | Return value |
| :------------ |:---------------|
| `ActiveModelSerializers::Adapter.adapter_map` | A Hash of all known adapters `{ adapter_name => adapter_class }` |
| `ActiveModelSerializers::Adapter.adapters` | A (sorted) Array of all known `adapter_names` |
| `ActiveModelSerializers::Adapter.lookup(name_or_klass)` | The `adapter_class`, else raises an `ActiveModelSerializers::Adapter::UnknownAdapter` error |
| `ActiveModelSerializers::Adapter.adapter_class(adapter)` | Delegates to `ActiveModelSerializers::Adapter.lookup(adapter)` |
| `ActiveModelSerializers::Adapter.configured_adapter` | A convenience method for `ActiveModelSerializers::Adapter.lookup(config.adapter)` |
The registered adapter name is always a String, but may be looked up as a Symbol or String.
Helpfully, the Symbol or String is underscored, so that `get(:my_adapter)` and `get("MyAdapter")`
may both be used.
For more information, see [the Adapter class on GitHub](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model_serializers/adapter.rb)

View File

@ -1,58 +0,0 @@
[Back to Guides](../README.md)
# Caching
## Warning
There is currently a problem with caching in AMS [Caching doesn't improve performance](https://github.com/rails-api/active_model_serializers/issues/1586). Adding caching _may_ slow down your application, rather than speeding it up. We suggest you benchmark any caching you implement before using in a production enviroment
___
To cache a serializer, call ```cache``` and pass its options.
The options are the same options of ```ActiveSupport::Cache::Store```, plus
a ```key``` option that will be the prefix of the object cache
on a pattern ```"#{key}/#{object.id}-#{object.updated_at}"```.
The cache support is optimized to use the cached object in multiple request. An object cached on a ```show``` request will be reused at the ```index```. If there is a relationship with another cached serializer it will also be created and reused automatically.
**[NOTE] Every object is individually cached.**
**[NOTE] The cache is automatically expired after an object is updated, but it's not deleted.**
```ruby
cache(options = nil) # options: ```{key, expires_in, compress, force, race_condition_ttl}```
```
Take the example below:
```ruby
class PostSerializer < ActiveModel::Serializer
cache key: 'post', expires_in: 3.hours
attributes :title, :body
has_many :comments
end
```
On this example every ```Post``` object will be cached with
the key ```"post/#{post.id}-#{post.updated_at}"```. You can use this key to expire it as you want,
but in this case it will be automatically expired after 3 hours.
## Fragment Caching
If there is some API endpoint that shouldn't be fully cached, you can still optimise it, using Fragment Cache on the attributes and relationships that you want to cache.
You can define the attribute by using ```only``` or ```except``` option on cache method.
**[NOTE] Cache serializers will be used at their relationships**
Example:
```ruby
class PostSerializer < ActiveModel::Serializer
cache key: 'post', expires_in: 3.hours, only: [:title]
attributes :title, :body
has_many :comments
end
```

View File

@ -1,169 +0,0 @@
[Back to Guides](../README.md)
# Configuration Options
The following configuration options can be set on
`ActiveModelSerializers.config`, preferably inside an initializer.
## General
##### adapter
The [adapter](adapters.md) to use.
Possible values:
- `:attributes` (default)
- `:json`
- `:json_api`
##### serializer_lookup_enabled
Enable automatic serializer lookup.
Possible values:
- `true` (default)
- `false`
When `false`, serializers must be explicitly specified.
##### key_transform
The [key transform](key_transforms.md) to use.
| Option | Result |
|----|----|
| `:camel` | ExampleKey |
| `:camel_lower` | exampleKey |
| `:dash` | example-key |
| `:unaltered` | the original, unaltered key |
| `:underscore` | example_key |
| `nil` | use the adapter default |
Each adapter has a default key transform configured:
| Adapter | Default Key Transform |
|----|----|
| `Attributes` | `:unaltered` |
| `Json` | `:unaltered` |
| `JsonApi` | `:dash` |
`config.key_transform` is a global override of the adapter default. Adapters
still prefer the render option `:key_transform` over this setting.
*NOTE: Key transforms can be expensive operations. If key transforms are unnecessary for the
application, setting `config.key_transform` to `:unaltered` will provide a performance boost.*
##### default_includes
What relationships to serialize by default. Default: `'*'`, which includes one level of related
objects. See [includes](adapters.md#included) for more info.
##### serializer_lookup_chain
Configures how serializers are searched for. By default, the lookup chain is
```ruby
ActiveModelSerializers::LookupChain::DEFAULT
```
which is shorthand for
```ruby
[
ActiveModelSerializers::LookupChain::BY_PARENT_SERIALIZER,
ActiveModelSerializers::LookupChain::BY_NAMESPACE,
ActiveModelSerializers::LookupChain::BY_RESOURCE_NAMESPACE,
ActiveModelSerializers::LookupChain::BY_RESOURCE
]
```
Each of the array entries represent a proc. A serializer lookup proc will be yielded 3 arguments. `resource_class`, `serializer_class`, and `namespace`.
Note that:
- `resource_class` is the class of the resource being rendered
- by default `serializer_class` is `ActiveModel::Serializer`
- for association lookup it's the "parent" serializer
- `namespace` correspond to either the controller namespace or the [optionally] specified [namespace render option](./rendering.md#namespace)
An example config could be:
```ruby
ActiveModelSerializers.config.serializer_lookup_chain = [
lambda do |resource_class, serializer_class, namespace|
"API::#{namespace}::#{resource_class}"
end
]
```
If you simply want to add to the existing lookup_chain. Use `unshift`.
```ruby
ActiveModelSerializers.config.serializer_lookup_chain.unshift(
lambda do |resource_class, serializer_class, namespace|
# ...
end
)
```
See [lookup_chain.rb](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model_serializers/lookup_chain.rb) for further explanations and examples.
## JSON API
##### jsonapi_resource_type
Sets whether the [type](http://jsonapi.org/format/#document-resource-identifier-objects)
of the resource should be `singularized` or `pluralized` when it is not
[explicitly specified by the serializer](https://github.com/rails-api/active_model_serializers/blob/master/docs/general/serializers.md#type)
Possible values:
- `:singular`
- `:plural` (default)
##### jsonapi_namespace_separator
Sets separator string for namespaced models to render `type` attribute.
| Separator | Example: Admin::User |
|----|----|
| `'-'` (default) | 'admin-users'
| `'--'` (recommended) | 'admin--users'
See [Recommendation for dasherizing (kebab-case-ing) namespaced object, such as `Admin::User`](https://github.com/json-api/json-api/issues/850)
for more discussion.
##### jsonapi_include_toplevel_object
Include a [top level jsonapi member](http://jsonapi.org/format/#document-jsonapi-object)
in the response document.
Possible values:
- `true`
- `false` (default)
##### jsonapi_version
The latest version of the spec to which the API conforms.
Default: `'1.0'`.
*Used when `jsonapi_include_toplevel_object` is `true`*
##### jsonapi_toplevel_meta
Optional top-level metadata. Not included if empty.
Default: `{}`.
*Used when `jsonapi_include_toplevel_object` is `true`*
## Hooks
To run a hook when ActiveModelSerializers is loaded, use
`ActiveSupport.on_load(:action_controller) do end`

View File

@ -1,100 +0,0 @@
[Back to Guides](../README.md)
# Deserialization
This is currently an *experimental* feature. The interface may change.
## JSON API
The `ActiveModelSerializers::Deserialization` defines two methods (namely `jsonapi_parse` and `jsonapi_parse!`), which take a `Hash` or an instance of `ActionController::Parameters` representing a JSON API payload, and return a hash that can directly be used to create/update models. The bang version throws an `InvalidDocument` exception when parsing fails, whereas the "safe" version simply returns an empty hash.
- Parameters
- document: `Hash` or `ActionController::Parameters` instance
- options:
- only: `Array` of whitelisted fields
- except: `Array` of blacklisted fields
- keys: `Hash` of fields the name of which needs to be modified (e.g. `{ :author => :user, :date => :created_at }`)
Examples:
```ruby
class PostsController < ActionController::Base
def create
Post.create(create_params)
end
def create_params
ActiveModelSerializers::Deserialization.jsonapi_parse(params, only: [:title, :content, :author])
end
end
```
Given a JSON API document,
```
document = {
'data' => {
'id' => 1,
'type' => 'post',
'attributes' => {
'title' => 'Title 1',
'date' => '2015-12-20'
},
'relationships' => {
'author' => {
'data' => {
'type' => 'user',
'id' => '2'
}
},
'second_author' => {
'data' => nil
},
'comments' => {
'data' => [{
'type' => 'comment',
'id' => '3'
},{
'type' => 'comment',
'id' => '4'
}]
}
}
}
}
```
The entire document can be parsed without specifying any options:
```ruby
ActiveModelSerializers::Deserialization.jsonapi_parse(document)
#=>
# {
# title: 'Title 1',
# date: '2015-12-20',
# author_id: 2,
# second_author_id: nil
# comment_ids: [3, 4]
# }
```
and fields, relationships, and polymorphic relationships can be specified via the options:
```ruby
ActiveModelSerializers::Deserialization
.jsonapi_parse(document, only: [:title, :date, :author],
keys: { date: :published_at },
polymorphic: [:author])
#=>
# {
# title: 'Title 1',
# published_at: '2015-12-20',
# author_id: '2',
# author_type: 'user'
# }
```
## Attributes/Json
There is currently no deserialization for those adapters.

View File

@ -1,31 +0,0 @@
[Back to Guides](../README.md)
# Fields
If for any reason, you need to restrict the fields returned, you should use `fields` option.
For example, if you have a serializer like this
```ruby
class UserSerializer < ActiveModel::Serializer
attributes :access_token, :first_name, :last_name
end
```
and in a specific controller, you want to return `access_token` only, `fields` will help you:
```ruby
class AnonymousController < ApplicationController
def create
render json: User.create(activation_state: 'anonymous'), fields: [:access_token], status: 201
end
end
```
Note that this is only valid for the `json` and `attributes` adapter. For the `json_api` adapter, you would use
```ruby
render json: @user, fields: { users: [:access_token] }
```
Where `users` is the JSONAPI type.

View File

@ -1,133 +0,0 @@
[Back to Guides](../README.md)
# Getting Started
## Creating a Serializer
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
```
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:
```
$ rails g serializer post
```
The generated serializer will contain basic `attributes` and
`has_many`/`has_one`/`belongs_to` declarations, based on the model. For example:
```ruby
class PostSerializer < ActiveModel::Serializer
attributes :title, :body
has_many :comments
has_one :author
end
```
and
```ruby
class CommentSerializer < ActiveModel::Serializer
attributes :name, :body
belongs_to :post
end
```
The attribute names are a **whitelist** of attributes to be serialized.
The `has_many`, `has_one`, and `belongs_to` declarations describe relationships between
resources. By default, when you serialize a `Post`, you will get its `Comments`
as well.
For more information, see [Serializers](/docs/general/serializers.md).
### Namespaced Models
When serializing a model inside a namespace, such as `Api::V1::Post`, ActiveModelSerializers will expect the corresponding serializer to be inside the same namespace (namely `Api::V1::PostSerializer`).
### Model Associations and Nested Serializers
When declaring a serializer for a model with associations, such as:
```ruby
class PostSerializer < ActiveModel::Serializer
has_many :comments
end
```
ActiveModelSerializers will look for `PostSerializer::CommentSerializer` in priority, and fall back to `::CommentSerializer` in case the former does not exist. This allows for more control over the way a model gets serialized as an association of an other model.
For example, in the following situation:
```ruby
class CommentSerializer < ActiveModel::Serializer
attributes :body, :date, :nb_likes
end
class PostSerializer < ActiveModel::Serializer
has_many :comments
class CommentSerializer < ActiveModel::Serializer
attributes :body_short
end
end
```
ActiveModelSerializers will use `PostSerializer::CommentSerializer` (thus including only the `:body_short` attribute) when serializing a `Comment` as part of a `Post`, but use `::CommentSerializer` when serializing a `Comment` directly (thus including `:body, :date, :nb_likes`).
### Extending a Base `ApplicationSerializer`
By default, new serializers descend from `ActiveModel::Serializer`. However, if
you wish to share behavior across your serializers, you can create an
`ApplicationSerializer` at `app/serializers/application_serializer.rb`:
```ruby
class ApplicationSerializer < ActiveModel::Serializer
end
```
Then any newly-generated serializers will automatically descend from
`ApplicationSerializer`.
```
$ rails g serializer post
```
Now generates:
```ruby
class PostSerializer < ApplicationSerializer
attributes :id
end
````
## Rails Integration
ActiveModelSerializers will automatically integrate with your Rails app,
so you won't need to update your controller.
This is a example of how the controller will look:
```ruby
class PostsController < ApplicationController
def show
@post = Post.find(params[:id])
render json: @post
end
end
```
If you wish to use Rails url helpers for link generation, e.g., `link(:resources) { resources_url }`, ensure your application sets
`Rails.application.routes.default_url_options`.
```ruby
Rails.application.routes.default_url_options = {
host: 'example.com'
}
```

View File

@ -1,40 +0,0 @@
[Back to Guides](../README.md)
# Instrumentation
ActiveModelSerializers uses the
[ActiveSupport::Notification API](http://guides.rubyonrails.org/active_support_instrumentation.html#subscribing-to-an-event),
which allows for subscribing to events, such as for logging.
## Events
Name:
`render.active_model_serializers`
Payload (example):
```ruby
{
serializer: PostSerializer,
adapter: ActiveModelSerializers::Adapter::Attributes
}
```
Subscribing:
```ruby
ActiveSupport::Notifications.subscribe 'render.active_model_serializers' do |name, started, finished, unique_id, data|
# whatever
end
ActiveSupport::Notifications.subscribe 'render.active_model_serializers' do |*args|
event = ActiveSupport::Notifications::Event.new(*args)
# event.payload
# whatever
end
```
## [LogSubscriber](http://api.rubyonrails.org/classes/ActiveSupport/LogSubscriber.html)
ActiveModelSerializers includes an `ActiveModelSerializers::LogSubscriber` that attaches to
`render.active_model_serializers`.

View File

@ -1,40 +0,0 @@
[Back to Guides](../README.md)
# Key Transforms
Key Transforms modify the casing of keys and keys referenced in values in
serialized responses.
Provided key transforms:
| Option | Result |
|----|----|
| `:camel` | ExampleKey |
| `:camel_lower` | exampleKey |
| `:dash` | example-key |
| `:unaltered` | the original, unaltered key |
| `:underscore` | example_key |
| `nil` | use the adapter default |
Key translation precedence is as follows:
##### Adapter option
`key_transform` is provided as an option via render.
```render json: posts, each_serializer: PostSerializer, key_transform: :camel_lower```
##### Configuration option
`key_transform` is set in `ActiveModelSerializers.config.key_transform`.
```ActiveModelSerializers.config.key_transform = :camel_lower```
##### Adapter default
Each adapter has a default transform configured:
| Adapter | Default Key Transform |
|----|----|
| `Json` | `:unaltered` |
| `JsonApi` | `:dash` |

View File

@ -1,21 +0,0 @@
[Back to Guides](../README.md)
# Logging
The default logger in a Rails application will be `Rails.logger`.
When there is no `Rails.logger`, the default logger is an instance of
`ActiveSupport::TaggedLogging` logging to STDOUT.
You may customize the logger in an initializer, for example:
```ruby
ActiveModelSerializers.logger = Logger.new(STDOUT)
```
You can also disable the logger, just put this in `config/initializers/active_model_serializers.rb`:
```ruby
require 'active_model_serializers'
ActiveSupport::Notifications.unsubscribe(ActiveModelSerializers::Logging::RENDER_EVENT)
```

View File

@ -1,293 +0,0 @@
[Back to Guides](../README.md)
# Rendering
### Implicit Serializer
In your controllers, when you use `render :json`, Rails will now first search
for a serializer for the object and use it if available.
```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`.
### Explicit Serializer
If you wish to use a serializer other than the default, you can explicitly pass it to the renderer.
#### 1. For a resource:
```ruby
render json: @post, serializer: PostPreviewSerializer
```
#### 2. For a resource collection:
Specify the serializer for each resource with `each_serializer`
```ruby
render json: @posts, each_serializer: PostPreviewSerializer
```
The default serializer for collections is `CollectionSerializer`.
Specify the collection serializer with the `serializer` option.
```ruby
render json: @posts, serializer: CollectionSerializer, each_serializer: PostPreviewSerializer
```
## Serializing non-ActiveRecord objects
See [README](../../README.md#what-does-a-serializable-resource-look-like)
## SerializableResource options
See [README](../../README.md#activemodelserializersserializableresource)
### adapter_opts
#### fields
If you are using `json` or `attributes` adapter
```ruby
render json: @user, fields: [:access_token]
```
See [Fields](fields.md) for more information.
#### adapter
This option lets you explicitly set the adapter to be used by passing a registered adapter. Your options are `:attributes`, `:json`, and `:json_api`.
```
ActiveModel::Serializer.config.adapter = :json_api
```
#### key_transform
```render json: posts, each_serializer: PostSerializer, key_transform: :camel_lower```
See [Key Transforms](key_transforms.md) for more information.
#### meta
A `meta` member can be used to include non-standard meta-information. `meta` can
be utilized in several levels in a response.
##### Top-level
To set top-level `meta` in a response, specify it in the `render` call.
```ruby
render json: @post, meta: { total: 10 }
```
The key can be customized using `meta_key` option.
```ruby
render json: @post, meta: { total: 10 }, meta_key: "custom_meta"
```
`meta` will only be included in your response if you are using an Adapter that
supports `root`, e.g., `JsonApi` and `Json` adapters. The default adapter,
`Attributes` does not have `root`.
##### Resource-level
To set resource-level `meta` in a response, define meta in a serializer with one
of the following methods:
As a single, static string.
```ruby
meta stuff: 'value'
```
As a block containing a Hash.
```ruby
meta do
{
rating: 4,
comments_count: object.comments.count
}
end
```
#### links
If you wish to use Rails url helpers for link generation, e.g., `link(:resources) { resources_url }`, ensure your application sets
`Rails.application.routes.default_url_options`.
##### Top-level
JsonApi supports a [links object](http://jsonapi.org/format/#document-links) to be specified at top-level, that you can specify in the `render`:
```ruby
links_object = {
href: "http://example.com/api/posts",
meta: {
count: 10
}
}
render json: @posts, links: links_object
```
That's the result:
```json
{
"data": [
{
"type": "posts",
"id": "1",
"attributes": {
"title": "JSON API is awesome!",
"body": "You should be using JSON API",
"created": "2015-05-22T14:56:29.000Z",
"updated": "2015-05-22T14:56:28.000Z"
}
}
],
"links": {
"href": "http://example.com/api/posts",
"meta": {
"count": 10
}
}
}
```
This feature is specific to JsonApi, so you have to use the use the [JsonApi Adapter](adapters.md#jsonapi)
##### Resource-level
In your serializer, define each link in one of the following methods:
As a static string
```ruby
link :link_name, 'https://example.com/resource'
```
As a block to be evaluated. When using Rails, URL helpers are available.
Ensure your application sets `Rails.application.routes.default_url_options`.
```ruby
link :link_name_ do
"https://example.com/resource/#{object.id}"
end
link(:link_name) { "https://example.com/resource/#{object.id}" }
link(:link_name) { resource_url(object) }
link(:link_name) { url_for(controller: 'controller_name', action: 'index', only_path: false) }
```
### serializer_opts
#### include
See [Adapters: Include Option](/docs/general/adapters.md#include-option).
#### Overriding the root key
Overriding the resource root only applies when using the JSON adapter.
Normally, the resource root is derived from the class name of the resource being serialized.
e.g. `UserPostSerializer.new(UserPost.new)` will be serialized with the root `user_post` or `user_posts` according the adapter collection pluralization rules.
When using the JSON adapter in your initializer (ActiveModelSerializers.config.adapter = :json), or passing in the adapter in your render call, you can specify the root by passing it as an argument to `render`. For example:
```ruby
render json: @user_post, root: "admin_post", adapter: :json
```
This will be rendered as:
```json
{
"admin_post": {
"title": "how to do open source"
}
}
```
Note: the `Attributes` adapter (default) does not include a resource root. You also will not be able to create a single top-level root if you are using the :json_api adapter.
#### namespace
The namespace for serializer lookup is based on the controller.
To configure the implicit namespace, in your controller, create a before filter
```ruby
before_action do
self.namespace_for_serializer = Api::V2
end
```
`namespace` can also be passed in as a render option:
```ruby
@post = Post.first
render json: @post, namespace: Api::V2
```
This tells the serializer lookup to check for the existence of `Api::V2::PostSerializer`, and if any relations are rendered with `@post`, they will also utilize the `Api::V2` namespace.
The `namespace` can be any object whose namespace can be represented by string interpolation (i.e. by calling to_s)
- Module `Api::V2`
- String `'Api::V2'`
- Symbol `:'Api::V2'`
Note that by using a string and symbol, Ruby will assume the namespace is defined at the top level.
#### serializer
Specify which serializer to use if you want to use a serializer other than the default.
For a single resource:
```ruby
@post = Post.first
render json: @post, serializer: SpecialPostSerializer
```
To specify which serializer to use on individual items in a collection (i.e., an `index` action), use `each_serializer`:
```ruby
@posts = Post.all
render json: @posts, each_serializer: SpecialPostSerializer
```
#### scope
See [Serializers: Scope](/docs/general/serializers.md#scope).
#### scope_name
See [Serializers: Scope](/docs/general/serializers.md#scope).
## Using a serializer without `render`
See [Usage outside of a controller](../howto/outside_controller_use.md#serializing-before-controller-render).
## Pagination
See [How to add pagination links](https://github.com/rails-api/active_model_serializers/blob/master/docs/howto/add_pagination_links.md).

View File

@ -1,480 +0,0 @@
[Back to Guides](../README.md)
# Serializers
Given a serializer class:
```ruby
class SomeSerializer < ActiveModel::Serializer
end
```
The following methods may be defined in it:
### Attributes
#### ::attributes
Serialization of the resource `title` and `body`
| In Serializer | #attributes |
|---------------------------- |-------------|
| `attributes :title, :body` | `{ title: 'Some Title', body: 'Some Body' }`
| `attributes :title, :body`<br>`def body "Special #{object.body}" end` | `{ title: 'Some Title', body: 'Special Some Body' }`
#### ::attribute
Serialization of the resource `title`
| In Serializer | #attributes |
|---------------------------- |-------------|
| `attribute :title` | `{ title: 'Some Title' } `
| `attribute :title, key: :name` | `{ name: 'Some Title' } `
| `attribute(:title) { 'A Different Title'}` | `{ title: 'A Different Title' } `
| `attribute :title`<br>`def title 'A Different Title' end` | `{ title: 'A Different Title' }`
An `if` or `unless` option can make an attribute conditional. It takes a symbol of a method name on the serializer, or a lambda literal.
e.g.
```ruby
attribute :private_data, if: :is_current_user?
attribute :another_private_data, if: -> { scope.admin? }
def is_current_user?
object.id == current_user.id
end
```
### Associations
The interface for associations is, generically:
> `association_type(association_name, options, &block)`
Where:
- `association_type` may be `has_one`, `has_many`, `belongs_to`.
- `association_name` is a method name the serializer calls.
- optional: `options` may be:
- `key:` The name used for the serialized association.
- `serializer:`
- `if:`
- `unless:`
- `virtual_value:`
- `polymorphic:` defines if polymorphic relation type should be nested in serialized association.
- `type:` the resource type as used by JSON:API, especially on a `belongs_to` relationship.
- `class_name:` used to determine `type` when `type` not given
- `foreign_key:` used by JSON:API on a `belongs_to` relationship to avoid unnecessarily loading the association object.
- `namespace:` used when looking up the serializer and `serializer` is not given. Falls back to the parent serializer's `:namespace` instance options, which, when present, comes from the render options. See [Rendering#namespace](rendering.md#namespace] for more details.
- optional: `&block` is a context that returns the association's attributes.
- prevents `association_name` method from being called.
- return value of block is used as the association value.
- yields the `serializer` to the block.
- `include_data false` prevents the `data` key from being rendered in the JSON API relationship.
#### ::has_one
e.g.
```ruby
has_one :bio
has_one :blog, key: :site
has_one :maker, virtual_value: { id: 1 }
has_one :blog do |serializer|
serializer.cached_blog
end
def cached_blog
cache_store.fetch("cached_blog:#{object.updated_at}") do
Blog.find(object.blog_id)
end
end
```
```ruby
has_one :blog, if: :show_blog?
# you can also use a string or lambda
# has_one :blog, if: 'scope.admin?'
# has_one :blog, if: -> (serializer) { serializer.scope.admin? }
# has_one :blog, if: -> { scope.admin? }
def show_blog?
scope.admin?
end
```
#### ::has_many
e.g.
```ruby
has_many :comments
has_many :comments, key: :reviews
has_many :comments, serializer: CommentPreviewSerializer
has_many :reviews, virtual_value: [{ id: 1 }, { id: 2 }]
has_many :comments, key: :last_comments do
last(1)
end
```
#### ::belongs_to
e.g.
```ruby
belongs_to :author, serializer: AuthorPreviewSerializer
belongs_to :author, key: :writer
belongs_to :post
belongs_to :blog
def blog
Blog.new(id: 999, name: 'Custom blog')
end
```
### Polymorphic Relationships
Polymorphic relationships are serialized by specifying the relationship, like any other association. For example:
```ruby
class PictureSerializer < ActiveModel::Serializer
has_one :imageable
end
```
You can specify the serializers by [overriding serializer_for](serializers.md#overriding-association-serializer-lookup). For more context about polymorphic relationships, see the [tests](../../test/adapter/polymorphic_test.rb) for each adapter.
### Caching
#### ::cache
e.g.
```ruby
cache key: 'post', expires_in: 0.1, skip_digest: true
cache expires_in: 1.day, skip_digest: true
cache key: 'writer', skip_digest: true
cache only: [:name], skip_digest: true
cache except: [:content], skip_digest: true
cache key: 'blog'
cache only: [:id]
```
#### #cache_key
e.g.
```ruby
# Uses a custom non-time-based cache key
def cache_key
"#{self.class.name.downcase}/#{self.id}"
end
```
### Other
#### ::type
When using the `:json_api` adapter, the `::type` method defines the JSONAPI [type](http://jsonapi.org/format/#document-resource-object-identification) that will be rendered for this serializer.
When using the `:json` adapter, the `::type` method defines the name of the root element.
It either takes a `String` or `Symbol` as parameter.
Note: This method is useful only when using the `:json_api` or `:json` adapter.
Examples:
```ruby
class UserProfileSerializer < ActiveModel::Serializer
type 'profile'
attribute :name
end
class AuthorProfileSerializer < ActiveModel::Serializer
type :profile
attribute :name
end
```
With the `:json_api` adapter, the previous serializers would be rendered as:
``` json
{
"data": {
"id": "1",
"type": "profile",
"attributes": {
"name": "Julia"
}
}
}
```
With the `:json` adapter, the previous serializer would be rendered as:
``` json
{
"profile": {
"name": "Julia"
}
}
```
#### ::link
```ruby
link :self do
href "https://example.com/link_author/#{object.id}"
end
link(:author) { link_author_url(object) }
link(:link_authors) { link_authors_url }
link :other, 'https://example.com/resource'
link(:posts) { link_author_posts_url(object) }
```
#### #object
The object being serialized.
#### #root
Resource root which is included in `JSON` adapter. As you can see at [Adapters Document](adapters.md), `Attribute` adapter (default) and `JSON API` adapter does not include root at top level.
By default, the resource root comes from the `model_name` of the serialized object's class.
There are several ways to specify root:
* [Overriding the root key](rendering.md#overriding-the-root-key)
* [Setting `type`](serializers.md#type)
* Specifying the `root` option, e.g. `root: 'specific_name'`, during the serializer's initialization:
```ruby
ActiveModelSerializers::SerializableResource.new(foo, root: 'bar')
```
#### #scope
Allows you to include in the serializer access to an external method.
It's intended to provide an authorization context to the serializer, so that
you may e.g. show an admin all comments on a post, else only published comments.
- `scope` is a method on the serializer instance that comes from `options[:scope]`. It may be nil.
- `scope_name` is an option passed to the new serializer (`options[:scope_name]`). The serializer
defines a method with that name that calls the `scope`, e.g. `def current_user; scope; end`.
Note: it does not define the method if the serializer instance responds to it.
That's a lot of words, so here's some examples:
First, let's assume the serializer is instantiated in the controller, since that's the usual scenario.
We'll refer to the serialization context as `controller`.
| options | `Serializer#scope` | method definition |
|-------- | ------------------|--------------------|
| `scope: current_user, scope_name: :current_user` | `current_user` | `Serializer#current_user` calls `controller.current_user`
| `scope: view_context, scope_name: :view_context` | `view_context` | `Serializer#view_context` calls `controller.view_context`
We can take advantage of the scope to customize the objects returned based
on the current user (scope).
For example, we can limit the posts the current user sees to those they created:
```ruby
class PostSerializer < ActiveModel::Serializer
attributes :id, :title, :body
# scope comments to those created_by the current user
has_many :comments do
object.comments.where(created_by: current_user)
end
end
```
Whether you write the method as above or as `object.comments.where(created_by: scope)`
is a matter of preference (assuming `scope_name` has been set).
##### Controller Authorization Context
In the controller, the scope/scope_name options are equal to
the [`serialization_scope`method](https://github.com/rails-api/active_model_serializers/blob/d02cd30fe55a3ea85e1d351b6e039620903c1871/lib/action_controller/serialization.rb#L13-L20),
which is `:current_user`, by default.
Specifically, the `scope_name` is defaulted to `:current_user`, and may be set as
`serialization_scope :view_context`. The `scope` is set to `send(scope_name)` when `scope_name` is
present and the controller responds to `scope_name`.
Thus, in a serializer, the controller provides `current_user` as the
current authorization scope when you call `render :json`.
**IMPORTANT**: Since the scope is set at render, you may want to customize it so that `current_user` isn't
called on every request. This was [also a problem](https://github.com/rails-api/active_model_serializers/pull/1252#issuecomment-159810477)
in [`0.9`](https://github.com/rails-api/active_model_serializers/tree/0-9-stable#customizing-scope).
We can change the scope from `current_user` to `view_context`.
```diff
class SomeController < ActionController::Base
+ serialization_scope :view_context
def current_user
User.new(id: 2, name: 'Bob', admin: true)
end
def edit
user = User.new(id: 1, name: 'Pete')
render json: user, serializer: AdminUserSerializer, adapter: :json_api
end
end
```
We could then use the controller method `view_context` in our serializer, like so:
```diff
class AdminUserSerializer < ActiveModel::Serializer
attributes :id, :name, :can_edit
def can_edit?
+ view_context.current_user.admin?
end
end
```
So that when we render the `#edit` action, we'll get
```json
{"data":{"id":"1","type":"users","attributes":{"name":"Pete","can_edit":true}}}
```
Where `can_edit` is `view_context.current_user.admin?` (true).
You can also tell what to set as `serialization_scope` for specific actions.
For example, use `admin_user` only for `Admin::PostSerializer` and `current_user` for rest.
```ruby
class PostsController < ActionController::Base
before_action only: :edit do
self.class.serialization_scope :admin_user
end
def show
render json: @post, serializer: PostSerializer
end
def edit
@post.save
render json: @post, serializer: Admin::PostSerializer
end
private
def admin_user
User.new(id: 2, name: 'Bob', admin: true)
end
def current_user
User.new(id: 2, name: 'Bob', admin: false)
end
end
```
#### #read_attribute_for_serialization(key)
The serialized value for a given key. e.g. `read_attribute_for_serialization(:title) #=> 'Hello World'`
#### #links
Allows you to modify the `links` node. By default, this node will be populated with the attributes set using the [::link](#link) method. Using `links: nil` will remove the `links` node.
```ruby
ActiveModelSerializers::SerializableResource.new(
@post,
adapter: :json_api,
links: {
self: {
href: 'http://example.com/posts',
meta: {
stuff: 'value'
}
}
}
)
```
#### #json_key
Returns the key used by the adapter as the resource root. See [root](#root) for more information.
## Examples
Given two models, a `Post(title: string, body: text)` and a
`Comment(name: string, body: text, post_id: integer)`, you will have two
serializers:
```ruby
class PostSerializer < ActiveModel::Serializer
cache key: 'posts', expires_in: 3.hours
attributes :title, :body
has_many :comments
end
```
and
```ruby
class CommentSerializer < ActiveModel::Serializer
attributes :name, :body
belongs_to :post
end
```
Generally speaking, you, as a user of ActiveModelSerializers, will write (or generate) these
serializer classes.
## More Info
For more information, see [the Serializer class on GitHub](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model/serializer.rb)
## Overriding association methods
To override an association, call `has_many`, `has_one` or `belongs_to` with a block:
```ruby
class PostSerializer < ActiveModel::Serializer
has_many :comments do
object.comments.active
end
end
```
## Overriding attribute methods
To override an attribute, call `attribute` with a block:
```ruby
class PostSerializer < ActiveModel::Serializer
attribute :body do
object.body.downcase
end
end
```
## Overriding association serializer lookup
If you want to define a specific serializer lookup for your associations, you can override
the `ActiveModel::Serializer.serializer_for` method to return a serializer class based on defined conditions.
```ruby
class MySerializer < ActiveModel::Serializer
def self.serializer_for(model, options)
return SparseAdminSerializer if model.class == 'Admin'
super
end
# the rest of the serializer
end
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 276 KiB

View File

@ -1,138 +0,0 @@
[Back to Guides](../README.md)
# How to add pagination links
### JSON API adapter
Pagination links will be included in your response automatically as long as
the resource is paginated and if you are using the ```JsonApi``` adapter.
If you want pagination links in your response, use [Kaminari](https://github.com/amatsuda/kaminari)
or [WillPaginate](https://github.com/mislav/will_paginate).
Although the other adapters do not have this feature, it is possible to
implement pagination links to `JSON` adapter. For more information about it,
please check our docs.
###### Kaminari examples
```ruby
#array
@posts = Kaminari.paginate_array([1, 2, 3]).page(3).per(1)
render json: @posts
#active_record
@posts = Post.page(3).per(1)
render json: @posts
```
###### WillPaginate examples
```ruby
#array
@posts = [1,2,3].paginate(page: 3, per_page: 1)
render json: @posts
#active_record
@posts = Post.page(3).per_page(1)
render json: @posts
```
```ruby
ActiveModelSerializers.config.adapter = :json_api
```
ex:
```json
{
"data": [
{
"type": "articles",
"id": "3",
"attributes": {
"title": "JSON API paints my bikeshed!",
"body": "The shortest article. Ever.",
"created": "2015-05-22T14:56:29.000Z",
"updated": "2015-05-22T14:56:28.000Z"
}
}
],
"links": {
"self": "http://example.com/articles?page[number]=3&page[size]=1",
"first": "http://example.com/articles?page[number]=1&page[size]=1",
"prev": "http://example.com/articles?page[number]=2&page[size]=1",
"next": "http://example.com/articles?page[number]=4&page[size]=1",
"last": "http://example.com/articles?page[number]=13&page[size]=1"
}
}
```
ActiveModelSerializers pagination relies on a paginated collection with the methods `current_page`, `total_pages`, and `size`, such as are supported by both [Kaminari](https://github.com/amatsuda/kaminari) or [WillPaginate](https://github.com/mislav/will_paginate).
### JSON adapter
If you are not using `JSON` adapter, pagination links will not be included automatically, but it is possible to do so using `meta` key.
Add this method to your base API controller.
```ruby
def pagination_dict(collection)
{
current_page: collection.current_page,
next_page: collection.next_page,
prev_page: collection.prev_page, # use collection.previous_page when using will_paginate
total_pages: collection.total_pages,
total_count: collection.total_count
}
end
```
Then, use it on your render method.
```ruby
render json: posts, meta: pagination_dict(posts)
```
ex.
```json
{
"posts": [
{
"id": 2,
"title": "JSON API paints my bikeshed!",
"body": "The shortest article. Ever."
}
],
"meta": {
"current_page": 3,
"next_page": 4,
"prev_page": 2,
"total_pages": 10,
"total_count": 10
}
}
```
You can also achieve the same result if you have a helper method that adds the pagination info in the meta tag. For instance, in your action specify a custom serializer.
```ruby
render json: @posts, each_serializer: PostPreviewSerializer, meta: meta_attributes(@posts)
```
```ruby
#expects pagination!
def meta_attributes(collection, extra_meta = {})
{
current_page: collection.current_page,
next_page: collection.next_page,
prev_page: collection.prev_page, # use collection.previous_page when using will_paginate
total_pages: collection.total_pages,
total_count: collection.total_count
}.merge(extra_meta)
end
```
### Attributes adapter
This adapter does not allow us to use `meta` key, due to that it is not possible to add pagination links.

View File

@ -1,140 +0,0 @@
[Back to Guides](../README.md)
# How to add relationship links
ActiveModelSerializers offers you many ways to add links in your JSON, depending on your needs.
The most common use case for links is supporting nested resources.
The following examples are without included relationship data (`include` param is empty),
specifically the following Rails controller was used for these examples:
```ruby
class Api::V1::UsersController < ApplicationController
def show
render jsonapi: User.find(params[:id]),
serializer: Api::V1::UserSerializer,
include: []
end
end
```
Bear in mind though that ActiveModelSerializers are [framework-agnostic](outside_controller_use.md), Rails is just a common example here.
### Links as an attribute of a resource
**This is applicable to JSON and Attributes adapters**
You can define an attribute in the resource, named `links`.
```ruby
class Api::V1::UserSerializer < ActiveModel::Serializer
include Rails.application.routes.url_helpers
attributes :id, :name
attribute :links do
id = object.id
{
self: api_v1_user_path(id),
microposts: api_v1_microposts_path(user_id: id)
}
end
end
```
Using the `JSON` adapter, this will result in:
```json
{
"user": {
"id": "1",
"name": "John",
"links": {
"self": "/api/v1/users/1",
"microposts": "/api/v1/microposts?user_id=1"
}
}
}
```
### Links as a property of the resource definiton
**This is only applicable to JSONAPI adapter**
You can use the `link` class method to define the links you need in the resource's primary data.
```ruby
class Api::V1::UserSerializer < ActiveModel::Serializer
attributes :id, :name
link(:self) { api_v1_user_path(object.id) }
link(:microposts) { api_v1_microposts_path(user_id: object.id) }
end
```
Using the `JSONAPI` adapter, this will result in:
```json
{
"data": {
"id": "1",
"type": "users",
"attributes": {
"name": "Example User"
},
"links": {
"self": "/api/v1/users/1",
"microposts": "/api/v1/microposts?user_id=1"
}
}
}
```
### Links that follow the JSONAPI spec
**This is only applicable to JSONAPI adapter**
If you have a JSONAPI-strict client that you are working with (like `ember-data`)
you need to construct the links inside the relationships. Also the link to fetch the
relationship data must be under the `related` attribute, whereas to manipulate the
relationship (in case of many-to-many relationship) must be under the `self` attribute.
You can find more info in the [spec](http://jsonapi.org/format/#document-resource-object-relationships).
Here is how you can do this:
```ruby
class Api::V1::UserSerializer < ActiveModel::Serializer
attributes :id, :name
has_many :microposts, serializer: Api::V1::MicropostSerializer do
link(:related) { api_v1_microposts_path(user_id: object.id) }
microposts = object.microposts
# The following code is needed to avoid n+1 queries.
# Core devs are working to remove this necessity.
# See: https://github.com/rails-api/active_model_serializers/issues/1325
microposts.loaded? ? microposts : microposts.none
end
end
```
This will result in:
```json
{
"data": {
"id": "1",
"type": "users",
"attributes": {
"name": "Example User"
},
"relationships": {
"microposts": {
"data": [],
"links": {
"related": "/api/v1/microposts?user_id=1"
}
}
}
}
}
```

View File

@ -1,55 +0,0 @@
[Back to Guides](../README.md)
# How to add root key
Add the root key to your API is quite simple with ActiveModelSerializers. The **Adapter** is what determines the format of your JSON response. The default adapter is the ```Attributes``` which doesn't have the root key, so your response is something similar to:
```json
{
"id": 1,
"title": "Awesome Post Tile",
"content": "Post content"
}
```
In order to add the root key you need to use the ```JSON``` Adapter, you can change this in an initializer:
```ruby
ActiveModelSerializers.config.adapter = :json
```
You can also specify a class as adapter, as long as it complies with the ActiveModelSerializers adapters interface.
It will add the root key to all your serialized endpoints.
ex:
```json
{
"post": {
"id": 1,
"title": "Awesome Post Tile",
"content": "Post content"
}
}
```
or if it returns a collection:
```json
{
"posts": [
{
"id": 1,
"title": "Awesome Post Tile",
"content": "Post content"
},
{
"id": 2,
"title": "Another Post Tile",
"content": "Another post content"
}
]
}
```
[There are several ways to specify root](../general/serializers.md#root) when using the JSON adapter.

View File

@ -1,42 +0,0 @@
[Back to Guides](../README.md)
The ActiveModelSerializers grape formatter relies on the existence of `env['grape.request']` which is implemeted by `Grape::Middleware::Globals`. You can meet his dependency by calling it before mounting the endpoints.
In the simpliest way:
```
class API < Grape::API
# @note Make sure this is above you're first +mount+
use Grape::Middleware::Globals
end
```
or more like what is shown in current Grape tutorials:
```
module MyApi
class ApiBase < Grape::API
use Grape::Middleware::Globals
require 'grape/active_model_serializers'
include Grape::ActiveModelSerializers
mount MyApi::V1::ApiBase
end
end
```
You could meet this dependency with your own middleware. The invocation might look like:
```
module MyApi
class ApiBase < Grape::API
use My::Middleware::Thingamabob
require 'grape/active_model_serializers'
include Grape::ActiveModelSerializers
mount MyApi::V1::ApiBase
end
end
```

View File

@ -1,66 +0,0 @@
[Back to Guides](../README.md)
## Using ActiveModelSerializers Outside Of A Controller
### Serializing a resource
In ActiveModelSerializers versions 0.10 or later, serializing resources outside of the controller context is fairly simple:
```ruby
# Create our resource
post = Post.create(title: "Sample post", body: "I love Active Model Serializers!")
# Optional options parameters for both the serializer and instance
options = {serializer: PostDetailedSerializer, username: 'sample user'}
# Create a serializable resource instance
serializable_resource = ActiveModelSerializers::SerializableResource.new(post, options)
# Convert your resource into json
model_json = serializable_resource.as_json
```
The object that is passed to `ActiveModelSerializers::SerializableResource.new` can be a single resource or a collection.
The additional options are the same options that are passed [through controllers](../general/rendering.md#explicit-serializer).
### Looking up the Serializer for a Resource
If you want to retrieve the serializer class for a specific resource, you can do the following:
```ruby
# Create our resource
post = Post.create(title: "Another Example", body: "So much fun.")
# Optional options parameters
options = {}
# Retrieve the default serializer for posts
serializer = ActiveModel::Serializer.serializer_for(post, options)
```
You could also retrieve the serializer via:
```ruby
ActiveModelSerializers::SerializableResource.new(post, options).serializer
```
Both approaches will return the serializer class that will be used for the resource.
Additionally, you could retrieve the serializer instance for the resource via:
```ruby
ActiveModelSerializers::SerializableResource.new(post, options).serializer_instance
```
## Serializing before controller render
At times, you might want to use a serializer without rendering it to the view. For those cases, you can create an instance of `ActiveModelSerializers::SerializableResource` with
the resource you want to be serialized and call `.as_json`.
```ruby
def create
message = current_user.messages.create!(message_params)
message_json = ActiveModelSerializers::SerializableResource.new(message).as_json
MessageCreationWorker.perform(message_json)
head 204
end
```

View File

@ -1,27 +0,0 @@
[Back to Guides](../README.md)
# Passing Arbitrary Options To A Serializer
In addition to the [`serialization_scope`](../general/serializers.md#scope), any options passed to `render`
that are not reserved for the [adapter](../general/rendering.md#adapter_opts)
are available in the serializer as [instance_options](../general/serializers.md#instance_options).
For example, we could pass in a field, such as `user_id` into our serializer.
```ruby
# posts_controller.rb
class PostsController < ApplicationController
def dashboard
render json: @post, user_id: 12
end
end
# post_serializer.rb
class PostSerializer < ActiveModel::Serializer
attributes :id, :title, :body
def comments_by_me
Comments.where(user_id: instance_options[:user_id], post_id: object.id)
end
end
```

View File

@ -1,73 +0,0 @@
[Back to Guides](../README.md)
# How to serialize a Plain-Old Ruby Object (PORO)
When you are first getting started with ActiveModelSerializers, it may seem only `ActiveRecord::Base` objects can be serializable,
but pretty much any object can be serializable with ActiveModelSerializers.
Here is an example of a PORO that is serializable in most situations:
```ruby
# my_model.rb
class MyModel
alias :read_attribute_for_serialization :send
attr_accessor :id, :name, :level
def initialize(attributes)
@id = attributes[:id]
@name = attributes[:name]
@level = attributes[:level]
end
def self.model_name
@_model_name ||= ActiveModel::Name.new(self)
end
end
```
The [ActiveModel::Serializer::Lint::Tests](../../lib/active_model/serializer/lint.rb)
define and validate which methods ActiveModelSerializers expects to be implemented.
An implementation of the complete spec is included either for use or as reference:
[`ActiveModelSerializers::Model`](../../lib/active_model_serializers/model.rb).
You can use in production code that will make your PORO a lot cleaner.
The above code now becomes:
```ruby
# my_model.rb
class MyModel < ActiveModelSerializers::Model
attributes :id, :name, :level
end
```
The default serializer would be `MyModelSerializer`.
*IMPORTANT*: There is a surprising behavior (bug) in the current implementation of ActiveModelSerializers::Model that
prevents an accessor from modifying attributes on the instance. The fix for this bug
is a breaking change, so we have made an opt-in configuration.
New applications should set:
```ruby
ActiveModelSerializers::Model.derive_attributes_from_names_and_fix_accessors
```
Existing applications can use the fix *and* avoid breaking changes
by making a superclass for new models. For example:
```ruby
class SerializablePoro < ActiveModelSerializers::Model
derive_attributes_from_names_and_fix_accessors
end
```
So that `MyModel` above would inherit from `SerializablePoro`.
`derive_attributes_from_names_and_fix_accessors` prepends the `DeriveAttributesFromNamesAndFixAccessors`
module and does the following:
- `id` will *always* be in the attributes. (This is until we separate out the caching requirement for POROs.)
- Overwrites the `attributes` method to that it only returns declared attributes.
`attributes` will now be a frozen hash with indifferent access.
For more information, see [README: What does a 'serializable resource' look like?](../../README.md#what-does-a-serializable-resource-look-like).

View File

@ -1,154 +0,0 @@
[Back to Guides](../README.md)
# How to test
## Controller Serializer Usage
ActiveModelSerializers provides a `assert_serializer` method to be used on your controller tests to
assert that a specific serializer was used.
```ruby
class PostsControllerTest < ActionController::TestCase
test "should render post serializer" do
get :index
assert_serializer "PostSerializer"
end
end
```
See [ActiveModelSerializers::Test::Serializer](../../lib/active_model_serializers/test/serializer.rb)
for more examples and documentation.
## Serialization against a schema
### Dependencies
To use the `assert_response_schema` you need to have the
[`json_schema`](https://github.com/brandur/json_schema) on your Gemfile. Please
add it to your Gemfile and run `$ bundle install`.
### Minitest test helpers
ActiveModelSerializers provides a `assert_response_schema` method to be used on your controller tests to
assert the response against a [JSON Schema](http://json-schema.org/). Let's take
a look in an example.
```ruby
class PostsController < ApplicationController
def show
@post = Post.find(params[:id])
render json: @post
end
end
```
To test the `posts#show` response of this controller we need to create a file
named `test/support/schemas/posts/show.json`. The helper uses a naming convention
to locate the file.
This file is a JSON Schema representation of our response.
```json
{
"properties": {
"title" : { "type" : "string" },
"content" : { "type" : "string" }
}
}
```
With all in place we can go to our test and use the helper.
```ruby
class PostsControllerTest < ActionController::TestCase
test "should render right response" do
get :index
assert_response_schema
end
end
```
#### Load a custom schema
If we need to use another schema, for example when we have a namespaced API that
shows the same response, we can pass the path of the schema.
```ruby
module V1
class PostsController < ApplicationController
def show
@post = Post.find(params[:id])
render json: @post
end
end
end
```
```ruby
class V1::PostsControllerTest < ActionController::TestCase
test "should render right response" do
get :index
assert_response_schema('posts/show.json')
end
end
```
#### Change the schema path
By default all schemas are created at `test/support/schemas`. If we are using
RSpec for example we can change this to `spec/support/schemas` defining the
default schema path in an initializer.
```ruby
ActiveModelSerializers.config.schema_path = 'spec/support/schemas'
```
#### Using with the Herokus JSON Schema-based tools
To use the test helper with the [prmd](https://github.com/interagent/prmd) and
[committee](https://github.com/interagent/committee).
We need to change the schema path to the recommended by prmd:
```ruby
ActiveModelSerializers.config.schema_path = 'docs/schema/schemata'
```
We also need to structure our schemata according to Heroku's conventions
(e.g. including
[required metadata](https://github.com/interagent/prmd/blob/master/docs/schemata.md#meta-data)
and [links](https://github.com/interagent/prmd/blob/master/docs/schemata.md#links).
#### JSON Pointers
If we plan to use [JSON
Pointers](http://spacetelescope.github.io/understanding-json-schema/UnderstandingJSONSchema.pdf) we need to define the `id` attribute on the schema. Example:
```js
// attributes.json
{
"id": "file://attributes.json#",
"properties": {
"name" : { "type" : "string" },
"description" : { "type" : "string" }
}
}
```
```js
// show.json
{
"properties": {
"name": {
"$ref": "file://attributes.json#/properties/name"
},
"description": {
"$ref": "file://attributes.json#/properties/description"
}
}
}
```

View File

@ -1,265 +0,0 @@
[Back to Guides](../README.md)
# How to migrate from `0.8` to `0.10` safely
## Disclaimer
### Proceed at your own risk
This document attempts to outline steps to upgrade your app based on the collective experience of
developers who have done this already. It may not cover all edge cases and situations that may cause issues,
so please proceed with a certain level of caution.
## Overview
This document outlines the steps needed to migrate from `0.8` to `0.10`. The method described
below has been created via the collective knowledge of contributions of those who have done
the migration successfully. The method has been tested specifically for migrating from `0.8.3`
to `0.10.2`.
The high level approach is to upgrade to `0.10` and change all serializers to use
a backwards-compatible `ActiveModel::V08::Serializer`or `ActiveModel::V08::CollectionSerializer`
and a `ActiveModelSerializers::Adapter::V08Adapter`. After a few more manual changes, you should have the same
functionality as you had with `AMS 0.8`. Then, you can continue to develop in your app by creating
new serializers that don't use these backwards compatible versions and slowly migrate
existing serializers to the `0.10` versions as needed.
### `0.10` breaking changes
- Passing a serializer to `render json:` is no longer supported
```ruby
render json: CustomerSerializer.new(customer) # rendered in 0.8, errors in 0.10
```
- Passing a nil resource to serializer now fails
```ruby
CustomerSerializer.new(nil) # returned nil in 0.8, throws error in 0.10
```
- Attribute methods are no longer defined on the serializer, and must be explicitly
accessed through `object`
```ruby
class MySerializer
attributes :foo, :bar
def foo
bar + 1 # bar does not work, needs to be object.bar in 0.10
end
end
```
- `root` option to collection serializer behaves differently
```ruby
# in 0.8
ActiveModel::ArraySerializer.new(resources, root: "resources")
# resulted in { "resources": <serialized_resources> }, does not work in 0.10
```
- No default serializer when serializer doesn't exist
- `@options` changed to `instance_options`
- Nested relationships are no longer walked by default. Use the `:include` option at **controller `render`** level to specify what relationships to walk. E.g. `render json: @post, include: {comments: :author}` if you want the `author` relationship walked, otherwise the json would only include the post with comments. See: https://github.com/rails-api/active_model_serializers/pull/1127
- To emulate `0.8`'s walking of arbitrarily deep relationships use: `include: '**'`. E.g. `render json: @post, include: '**'`
## Steps to migrate
### 1. Upgrade the `active_model_serializer` gem in you `Gemfile`
Change to `gem 'active_model_serializers', '~> 0.10'` and run `bundle install`
### 2. Add `ActiveModel::V08::Serializer`
```ruby
module ActiveModel
module V08
class Serializer < ActiveModel::Serializer
include Rails.application.routes.url_helpers
# AMS 0.8 would delegate method calls from within the serializer to the
# object.
def method_missing(*args)
method = args.first
read_attribute_for_serialization(method)
end
alias_method :options, :instance_options
# Since attributes could be read from the `object` via `method_missing`,
# the `try` method did not behave as before. This patches `try` with the
# original implementation plus the addition of
# ` || object.respond_to?(a.first, true)` to check if the object responded to
# the given method.
def try(*a, &b)
if a.empty? || respond_to?(a.first, true) || object.respond_to?(a.first, true)
try!(*a, &b)
end
end
# AMS 0.8 would return nil if the serializer was initialized with a nil
# resource.
def serializable_hash(adapter_options = nil,
options = {},
adapter_instance =
self.class.serialization_adapter_instance)
object.nil? ? nil : super
end
end
end
end
```
Add this class to your app however you see fit. This is the class that your existing serializers
that inherit from `ActiveModel::Serializer` should inherit from.
### 3. Add `ActiveModel::V08::CollectionSerializer`
```ruby
module ActiveModel
module V08
class CollectionSerializer < ActiveModel::Serializer::CollectionSerializer
# In AMS 0.8, passing an ArraySerializer instance with a `root` option
# properly nested the serialized resources within the given root.
# Ex.
#
# class MyController < ActionController::Base
# def index
# render json: ActiveModel::Serializer::ArraySerializer
# .new(resources, root: "resources")
# end
# end
#
# Produced
#
# {
# "resources": [
# <serialized_resource>,
# ...
# ]
# }
def as_json(options = {})
if root
{
root => super
}
else
super
end
end
# AMS 0.8 used `DefaultSerializer` if it couldn't find a serializer for
# the given resource. When not using an adapter, this is not true in
# `0.10`
def serializer_from_resource(resource, serializer_context_class, options)
serializer_class =
options.fetch(:serializer) { serializer_context_class.serializer_for(resource) }
if serializer_class.nil? # rubocop:disable Style/GuardClause
DefaultSerializer.new(resource, options)
else
serializer_class.new(resource, options.except(:serializer))
end
end
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
end
end
```
Add this class to your app however you see fit. This is the class that existing uses of
`ActiveModel::ArraySerializer` should be changed to use.
### 4. Add `ActiveModelSerializers::Adapter::V08Adapter`
```ruby
module ActiveModelSerializers
module Adapter
class V08Adapter < ActiveModelSerializers::Adapter::Base
def serializable_hash(options = nil)
options ||= {}
if serializer.respond_to?(:each)
if serializer.root
delegate_to_json_adapter(options)
else
serializable_hash_for_collection(options)
end
else
serializable_hash_for_single_resource(options)
end
end
def serializable_hash_for_collection(options)
serializer.map do |s|
V08Adapter.new(s, instance_options)
.serializable_hash(options)
end
end
def serializable_hash_for_single_resource(options)
if serializer.object.is_a?(ActiveModel::Serializer)
# It is recommended that you add some logging here to indicate
# places that should get converted to eventually allow for this
# adapter to get removed.
@serializer = serializer.object
end
if serializer.root
delegate_to_json_adapter(options)
else
options = serialization_options(options)
serializer.serializable_hash(instance_options, options, self)
end
end
def delegate_to_json_adapter(options)
ActiveModelSerializers::Adapter::Json
.new(serializer, instance_options)
.serializable_hash(options)
end
end
end
end
```
Add this class to your app however you see fit.
Add
```ruby
ActiveModelSerializers.config.adapter =
ActiveModelSerializers::Adapter::V08Adapter
```
to `config/active_model_serializer.rb` to configure AMS to use this
class as the default adapter.
### 5. Change inheritors of `ActiveModel::Serializer` to inherit from `ActiveModel::V08::Serializer`
Simple find/replace
### 6. Remove `private` keyword from serializers
Simple find/replace. This is required to allow the `ActiveModel::V08::Serializer`
to have proper access to the methods defined in the serializer.
You may be able to change the `private` to `protected`, but this is hasn't been tested yet.
### 7. Remove references to `ActiveRecord::Base#active_model_serializer`
This method is no longer supported in `0.10`.
`0.10` does a good job of discovering serializers for `ActiveRecord` objects.
### 8. Rename `ActiveModel::ArraySerializer` to `ActiveModel::V08::CollectionSerializer`
Find/replace uses of `ActiveModel::ArraySerializer` with `ActiveModel::V08::CollectionSerializer`.
Also, be sure to change the `each_serializer` keyword to `serializer` when calling making the replacement.
### 9. Replace uses of `@options` to `instance_options` in serializers
Simple find/replace
## Conclusion
After you've done the steps above, you should test your app to ensure that everything is still working properly.
If you run into issues, please contribute back to this document so others can benefit from your knowledge.

View File

@ -1,147 +0,0 @@
[Back to Guides](../README.md)
# Integrating with Ember and JSON API
- [Preparation](./ember-and-json-api.md#preparation)
- [Server-Side Changes](./ember-and-json-api.md#server-side-changes)
- [Adapter Changes](./ember-and-json-api.md#adapter-changes)
- [Serializer Changes](./ember-and-json-api.md#serializer-changes)
- [Including Nested Resources](./ember-and-json-api.md#including-nested-resources)
## Preparation
Note: This guide assumes that `ember-cli` is used for your ember app.
The JSON API specification calls for hyphens for multi-word separators. ActiveModelSerializers uses underscores.
To solve this, in Ember, both the adapter and the serializer will need some modifications:
### Server-Side Changes
First, set the adapter type in an initializer file:
```ruby
# config/initializers/active_model_serializers.rb
ActiveModelSerializers.config.adapter = :json_api
```
or:
```ruby
# config/initializers/active_model_serializers.rb
ActiveModelSerializers.config.adapter = ActiveModelSerializers::Adapter::JsonApi
```
You will also want to set the `key_transform` to `:unaltered` since you will adjust the attributes in your Ember serializer to use underscores instead of dashes later. You could also use `:underscore`, but `:unaltered` is better for performance.
```ruby
# config/initializers/active_model_serializers.rb
ActiveModelSerializers.config.key_transform = :unaltered
```
In order to properly handle JSON API responses, we need to register a JSON API renderer, like so:
```ruby
# config/initializers/active_model_serializers.rb
ActiveSupport.on_load(:action_controller) do
require 'active_model_serializers/register_jsonapi_renderer'
end
```
Rails also requires your controller to tell it that you accept and generate JSONAPI data. To do that, you use `respond_to` in your controller handlers to tell rails you are consuming and returning jsonapi format data. Without this, Rails will refuse to parse the request body into params. You can add `ActionController::MimeResponds` to your application controller to enable this:
```ruby
class ApplicationController < ActionController::API
include ActionController::MimeResponds
end
```
Then, in your controller you can tell rails you're accepting and rendering the jsonapi format:
```ruby
# POST /post
def create
@post = Post.new(post_params)
respond_to do |format|
if @post.save
format.jsonapi { render jsonapi: @post, status: :created, location: @post }
else
format.jsonapi { render jsonapi: @post.errors, status: :unprocessable_entity }
end
end
end
# Only allow a trusted parameter "white list" through.
def post_params
ActiveModelSerializers::Deserialization.jsonapi_parse!(params, only: [:title, :body] )
end
end
```
#### Note:
In Rails 5, the "unsafe" method ( `jsonapi_parse!` vs the safe `jsonapi_parse`) throws an `InvalidDocument` exception when the payload does not meet basic criteria for JSON API deserialization.
### Adapter Changes
```javascript
// app/adapters/application.js
import Ember from 'ember';
import DS from 'ember-data';
import ENV from "../config/environment";
const { underscore, pluralize } = Ember.String;
export default DS.JSONAPIAdapter.extend({
namespace: 'api',
// if your rails app is on a different port from your ember app
// this can be helpful for development.
// in production, the host for both rails and ember should be the same.
host: ENV.host,
// allows the multiword paths in urls to be underscored
pathForType: function(type) {
let underscored = underscore(type);
return pluralize(underscored);
},
});
```
### Serializer Changes
```javascript
// app/serializers/application.js
import Ember from 'ember';
import DS from 'ember-data';
var underscore = Ember.String.underscore;
export default DS.JSONAPISerializer.extend({
keyForAttribute: function(attr) {
return underscore(attr);
},
keyForRelationship: function(rawKey) {
return underscore(rawKey);
}
});
```
## Including Nested Resources
Ember Data can request related records by using `include`. Below are some examples of how to make Ember Data request the inclusion of related records. For more on `include` usage, see: [The JSON API include examples](./../general/adapters.md#JSON-API)
```javascript
store.findRecord('post', postId, { include: 'comments' } );
```
which will generate the path /posts/{postId}?include='comments'
So then in your controller, you'll want to be sure to have something like:
```ruby
render jsonapi: @post, include: params[:include]
```
If you want to use `include` on a collection, you'd write something like this:
```javascript
store.query('post', { include: 'comments' });
```
which will generate the path `/posts?include='comments'`

View File

@ -1,19 +0,0 @@
# Integration with Grape
[Grape](https://github.com/ruby-grape/grape) is an opinionated micro-framework for creating REST-like APIs in ruby.
ActiveModelSerializers currently supports Grape >= 0.13, < 1.0
To add [Grape](https://github.com/ruby-grape/grape) support, enable the formatter and helper functions by including `Grape::ActiveModelSerializers` in your base endpoint. For example:
```ruby
module Example
class Dummy < Grape::API
require 'grape/active_model_serializers'
include Grape::ActiveModelSerializers
mount Example::V1::Base
end
end
```
Aside from this, [configuration](../general/configuration_options.md) of ActiveModelSerializers is exactly the same.

View File

@ -1,56 +0,0 @@
[Back to Guides](../README.md)
# [JSON API Errors](http://jsonapi.org/format/#errors)
Rendering error documents requires specifying the error serializer(s):
- Serializer:
- For a single resource: `serializer: ActiveModel::Serializer::ErrorSerializer`.
- For a collection: `serializer: ActiveModel::Serializer::ErrorsSerializer`, `each_serializer: ActiveModel::Serializer::ErrorSerializer`.
The resource **MUST** have a non-empty associated `#errors` object.
The `errors` object must have a `#messages` method that returns a hash of error name to array of
descriptions.
## Use in controllers
```ruby
resource = Profile.new(name: 'Name 1',
description: 'Description 1',
comments: 'Comments 1')
resource.errors.add(:name, 'cannot be nil')
resource.errors.add(:name, 'must be longer')
resource.errors.add(:id, 'must be a uuid')
render json: resource, status: 422, adapter: :json_api, serializer: ActiveModel::Serializer::ErrorSerializer
# #=>
# { :errors =>
# [
# { :source => { :pointer => '/data/attributes/name' }, :detail => 'cannot be nil' },
# { :source => { :pointer => '/data/attributes/name' }, :detail => 'must be longer' },
# { :source => { :pointer => '/data/attributes/id' }, :detail => 'must be a uuid' }
# ]
# }.to_json
```
## Direct error document generation
```ruby
options = nil
resource = ModelWithErrors.new
resource.errors.add(:name, 'must be awesome')
serializable_resource = ActiveModelSerializers::SerializableResource.new(
resource, {
serializer: ActiveModel::Serializer::ErrorSerializer,
adapter: :json_api
})
serializable_resource.as_json(options)
# #=>
# {
# :errors =>
# [
# { :source => { :pointer => '/data/attributes/name' }, :detail => 'must be awesome' }
# ]
# }
```

View File

@ -1,151 +0,0 @@
[Back to Guides](../README.md)
[![JSON API 1.0](https://img.shields.io/badge/JSON%20API-1.0-lightgrey.svg)](http://jsonapi.org/)
## JSON API Requests
- [Query Parameters Spec](http://jsonapi.org/format/#query-parameters)
Headers:
- Request: `Accept: application/vnd.api+json`
- Response: `Content-Type: application/vnd.api+json`
### [Fetching Data](http://jsonapi.org/format/#fetching)
A server MUST support fetching resource data for every URL provided as:
- a `self` link as part of the top-level links object
- a `self` link as part of a resource-level links object
- a `related` link as part of a relationship-level links object
Example supported requests
- Individual resource or collection
- GET /articles
- GET /articles/1
- GET /articles/1/author
- Relationships
- GET /articles/1/relationships/comments
- GET /articles/1/relationships/author
- Optional: [Inclusion of related resources](http://jsonapi.org/format/#fetching-includes) `JSONAPI::IncludeDirective`
- GET /articles/1?`include`=comments
- GET /articles/1?`include`=comments.author
- GET /articles/1?`include`=author,comments.author
- GET /articles/1/relationships/comments?`include`=comments.author
- Optional: [Sparse Fieldsets](http://jsonapi.org/format/#fetching-sparse-fieldsets) `ActiveModel::Serializer::Fieldset`
- GET /articles?`include`=author&`fields`[articles]=title,body&`fields`[people]=name
- Optional: [Sorting](http://jsonapi.org/format/#fetching-sorting)
- GET /people?`sort`=age
- GET /people?`sort`=age,author.name
- GET /articles?`sort`=-created,title
- Optional: [Pagination](http://jsonapi.org/format/#fetching-pagination)
- GET /articles?`page`[number]=3&`page`[size]=1
- Optional: [Filtering](http://jsonapi.org/format/#fetching-filtering)
- GET /comments?`filter`[post]=1
- GET /comments?`filter`[post]=1,2
- GET /comments?`filter`[post]=1,2
### [CRUD Actions](http://jsonapi.org/format/#crud)
### [Asynchronous Processing](http://jsonapi.org/recommendations/#asynchronous-processing)
### [Bulk Operations Extension](http://jsonapi.org/extensions/bulk/)
## JSON API Document Schema
| JSON API object | JSON API properties | Required | ActiveModelSerializers representation |
|-----------------------|----------------------------------------------------------------------------------------------------|----------|---------------------------------------|
| schema | oneOf (success, failure, info) | |
| success | data, included, meta, links, jsonapi | | AM::SerializableResource
| success.meta | meta | | AMS::Adapter::Base#meta
| success.included | UniqueArray(resource) | | AMS::Adapter::JsonApi#serializable_hash_for_collection
| success.data | data | |
| success.links | allOf (links, pagination) | | AMS::Adapter::JsonApi#links_for
| success.jsonapi | jsonapi | |
| failure | errors, meta, jsonapi | errors | AMS::Adapter::JsonApi#failure_document, #1004
| failure.errors | UniqueArray(error) | | AM::S::ErrorSerializer, #1004
| meta | Object | |
| data | oneOf (resource, UniqueArray(resource)) | | AMS::Adapter::JsonApi#serializable_hash_for_collection,#serializable_hash_for_single_resource
| resource | String(type), String(id),<br>attributes, relationships,<br>links, meta | type, id | AM::S::Adapter::JsonApi#primary_data_for
| links | Uri(self), Link(related) | | #1028, #1246, #1282
| link | oneOf (linkString, linkObject) | |
| link.linkString | Uri | |
| link.linkObject | Uri(href), meta | href |
| attributes | patternProperties(<br>`"^(?!relationships$|links$)\\w[-\\w_]*$"`),<br>any valid JSON | | AM::Serializer#attributes, AMS::Adapter::JsonApi#resource_object_for
| relationships | patternProperties(<br>`"^\\w[-\\w_]*$"`);<br>links, relationships.data, meta | | AMS::Adapter::JsonApi#relationships_for
| relationships.data | oneOf (relationshipToOne, relationshipToMany) | | AMS::Adapter::JsonApi#resource_identifier_for
| relationshipToOne | anyOf(empty, linkage) | |
| relationshipToMany | UniqueArray(linkage) | |
| empty | null | |
| linkage | String(type), String(id), meta | type, id | AMS::Adapter::JsonApi#primary_data_for
| pagination | pageObject(first), pageObject(last),<br>pageObject(prev), pageObject(next) | | AMS::Adapter::JsonApi::PaginationLinks#serializable_hash
| pagination.pageObject | oneOf(Uri, null) | |
| jsonapi | String(version), meta | | AMS::Adapter::JsonApi::Jsonapi#as_json
| error | String(id), links, String(status),<br>String(code), String(title),<br>String(detail), error.source, meta | | AM::S::ErrorSerializer, AMS::Adapter::JsonApi::Error.resource_errors
| error.source | String(pointer), String(parameter) | | AMS::Adapter::JsonApi::Error.error_source
| pointer | [JSON Pointer RFC6901](https://tools.ietf.org/html/rfc6901) | | AMS::JsonPointer
The [http://jsonapi.org/schema](schema/schema.json) makes a nice roadmap.
### Success Document
- [ ] success
- [ ] data: `"$ref": "#/definitions/data"`
- [ ] included: array of unique items of type `"$ref": "#/definitions/resource"`
- [ ] meta: `"$ref": "#/definitions/meta"`
- [ ] links:
- [ ] link: `"$ref": "#/definitions/links"`
- [ ] pagination: ` "$ref": "#/definitions/pagination"`
- [ ] jsonapi: ` "$ref": "#/definitions/jsonapi"`
### Failure Document
- [ ] failure
- [x] errors: array of unique items of type ` "$ref": "#/definitions/error"`
- [ ] meta: `"$ref": "#/definitions/meta"`
- [ ] jsonapi: `"$ref": "#/definitions/jsonapi"`
### Info Document
- [ ] info
- [ ] meta: `"$ref": "#/definitions/meta"`
- [ ] links: `"$ref": "#/definitions/links"`
- [ ] jsonapi: ` "$ref": "#/definitions/jsonapi"`
### Definitions
- [ ] definitions:
- [ ] meta
- [ ] data: oneOf (resource, array of unique resources)
- [ ] resource
- [ ] attributes
- [ ] relationships
- [ ] relationshipToOne
- [ ] empty
- [ ] linkage
- [ ] meta
- [ ] relationshipToMany
- [ ] linkage
- [ ] meta
- [ ] links
- [ ] meta
- [ ] links
- [ ] link
- [ ] uri
- [ ] href, meta
- [ ] pagination
- [ ] jsonapi
- [ ] meta
- [ ] error
- [ ] id: a unique identifier for this particular occurrence of the problem.
- [ ] links: a links object containing the following members:
- [ ] about: a link that leads to further details about this particular occurrence of the problem.
- [ ] status: the HTTP status code applicable to this problem, expressed as a string value.
- [ ] code: an application-specific error code, expressed as a string value.
- [ ] title: a short, human-readable summary of the problem that SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization.
- [x] detail: a human-readable explanation specific to this occurrence of the problem.
- [x] source: an object containing references to the source of the error, optionally including any of the following members:
- [x] pointer: a JSON Pointer [RFC6901](https://tools.ietf.org/html/rfc6901) to the associated entity in the request document [e.g. "/data" for a primary data object, or "/data/attributes/title" for a specific attribute].
- [x] parameter: a string indicating which query parameter caused the error.
- [ ] meta: a meta object containing non-standard meta-information about the error.

View File

@ -1,366 +0,0 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "JSON API Schema",
"description": "This is a schema for responses in the JSON API format. For more, see http://jsonapi.org",
"oneOf": [
{
"$ref": "#/definitions/success"
},
{
"$ref": "#/definitions/failure"
},
{
"$ref": "#/definitions/info"
}
],
"definitions": {
"success": {
"type": "object",
"required": [
"data"
],
"properties": {
"data": {
"$ref": "#/definitions/data"
},
"included": {
"description": "To reduce the number of HTTP requests, servers **MAY** allow responses that include related resources along with the requested primary resources. Such responses are called \"compound documents\".",
"type": "array",
"items": {
"$ref": "#/definitions/resource"
},
"uniqueItems": true
},
"meta": {
"$ref": "#/definitions/meta"
},
"links": {
"description": "Link members related to the primary data.",
"allOf": [
{
"$ref": "#/definitions/links"
},
{
"$ref": "#/definitions/pagination"
}
]
},
"jsonapi": {
"$ref": "#/definitions/jsonapi"
}
},
"additionalProperties": false
},
"failure": {
"type": "object",
"required": [
"errors"
],
"properties": {
"errors": {
"type": "array",
"items": {
"$ref": "#/definitions/error"
},
"uniqueItems": true
},
"meta": {
"$ref": "#/definitions/meta"
},
"jsonapi": {
"$ref": "#/definitions/jsonapi"
}
},
"additionalProperties": false
},
"info": {
"type": "object",
"required": [
"meta"
],
"properties": {
"meta": {
"$ref": "#/definitions/meta"
},
"links": {
"$ref": "#/definitions/links"
},
"jsonapi": {
"$ref": "#/definitions/jsonapi"
}
},
"additionalProperties": false
},
"meta": {
"description": "Non-standard meta-information that can not be represented as an attribute or relationship.",
"type": "object",
"additionalProperties": true
},
"data": {
"description": "The document's \"primary data\" is a representation of the resource or collection of resources targeted by a request.",
"oneOf": [
{
"$ref": "#/definitions/resource"
},
{
"description": "An array of resource objects, an array of resource identifier objects, or an empty array ([]), for requests that target resource collections.",
"type": "array",
"items": {
"$ref": "#/definitions/resource"
},
"uniqueItems": true
}
]
},
"resource": {
"description": "\"Resource objects\" appear in a JSON API document to represent resources.",
"type": "object",
"required": [
"type",
"id"
],
"properties": {
"type": {
"type": "string"
},
"id": {
"type": "string"
},
"attributes": {
"$ref": "#/definitions/attributes"
},
"relationships": {
"$ref": "#/definitions/relationships"
},
"links": {
"$ref": "#/definitions/links"
},
"meta": {
"$ref": "#/definitions/meta"
}
},
"additionalProperties": false
},
"links": {
"description": "A resource object **MAY** contain references to other resource objects (\"relationships\"). Relationships may be to-one or to-many. Relationships can be specified by including a member in a resource's links object.",
"type": "object",
"properties": {
"self": {
"description": "A `self` member, whose value is a URL for the relationship itself (a \"relationship URL\"). This URL allows the client to directly manipulate the relationship. For example, it would allow a client to remove an `author` from an `article` without deleting the people resource itself.",
"type": "string",
"format": "uri"
},
"related": {
"$ref": "#/definitions/link"
}
},
"additionalProperties": true
},
"link": {
"description": "A link **MUST** be represented as either: a string containing the link's URL or a link object.",
"oneOf": [
{
"description": "A string containing the link's URL.",
"type": "string",
"format": "uri"
},
{
"type": "object",
"required": [
"href"
],
"properties": {
"href": {
"description": "A string containing the link's URL.",
"type": "string",
"format": "uri"
},
"meta": {
"$ref": "#/definitions/meta"
}
}
}
]
},
"attributes": {
"description": "Members of the attributes object (\"attributes\") represent information about the resource object in which it's defined.",
"type": "object",
"patternProperties": {
"^(?!relationships$|links$)\\w[-\\w_]*$": {
"description": "Attributes may contain any valid JSON value."
}
},
"additionalProperties": false
},
"relationships": {
"description": "Members of the relationships object (\"relationships\") represent references from the resource object in which it's defined to other resource objects.",
"type": "object",
"patternProperties": {
"^\\w[-\\w_]*$": {
"properties": {
"links": {
"$ref": "#/definitions/links"
},
"data": {
"description": "Member, whose value represents \"resource linkage\".",
"oneOf": [
{
"$ref": "#/definitions/relationshipToOne"
},
{
"$ref": "#/definitions/relationshipToMany"
}
]
},
"meta": {
"$ref": "#/definitions/meta"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
"relationshipToOne": {
"description": "References to other resource objects in a to-one (\"relationship\"). Relationships can be specified by including a member in a resource's links object.",
"anyOf": [
{
"$ref": "#/definitions/empty"
},
{
"$ref": "#/definitions/linkage"
}
]
},
"relationshipToMany": {
"description": "An array of objects each containing \"type\" and \"id\" members for to-many relationships.",
"type": "array",
"items": {
"$ref": "#/definitions/linkage"
},
"uniqueItems": true
},
"empty": {
"description": "Describes an empty to-one relationship.",
"type": "null"
},
"linkage": {
"description": "The \"type\" and \"id\" to non-empty members.",
"type": "object",
"required": [
"type",
"id"
],
"properties": {
"type": {
"type": "string"
},
"id": {
"type": "string"
},
"meta": {
"$ref": "#/definitions/meta"
}
},
"additionalProperties": false
},
"pagination": {
"type": "object",
"properties": {
"first": {
"description": "The first page of data",
"oneOf": [
{ "type": "string", "format": "uri" },
{ "type": "null" }
]
},
"last": {
"description": "The last page of data",
"oneOf": [
{ "type": "string", "format": "uri" },
{ "type": "null" }
]
},
"prev": {
"description": "The previous page of data",
"oneOf": [
{ "type": "string", "format": "uri" },
{ "type": "null" }
]
},
"next": {
"description": "The next page of data",
"oneOf": [
{ "type": "string", "format": "uri" },
{ "type": "null" }
]
}
}
},
"jsonapi": {
"description": "An object describing the server's implementation",
"type": "object",
"properties": {
"version": {
"type": "string"
},
"meta": {
"$ref": "#/definitions/meta"
}
},
"additionalProperties": false
},
"error": {
"type": "object",
"properties": {
"id": {
"description": "A unique identifier for this particular occurrence of the problem.",
"type": "string"
},
"links": {
"$ref": "#/definitions/links"
},
"status": {
"description": "The HTTP status code applicable to this problem, expressed as a string value.",
"type": "string"
},
"code": {
"description": "An application-specific error code, expressed as a string value.",
"type": "string"
},
"title": {
"description": "A short, human-readable summary of the problem. It **SHOULD NOT** change from occurrence to occurrence of the problem, except for purposes of localization.",
"type": "string"
},
"detail": {
"description": "A human-readable explanation specific to this occurrence of the problem.",
"type": "string"
},
"source": {
"type": "object",
"properties": {
"pointer": {
"description": "A JSON Pointer [RFC6901] to the associated entity in the request document [e.g. \"/data\" for a primary data object, or \"/data/attributes/title\" for a specific attribute].",
"type": "string"
},
"parameter": {
"description": "A string indicating which query parameter caused the error.",
"type": "string"
}
}
},
"meta": {
"$ref": "#/definitions/meta"
}
},
"additionalProperties": false
}
}
}

View File

@ -1,106 +0,0 @@
- Start Date: (2015-10-29)
- RFC PR: https://github.com/rails-api/active_model_serializers/pull/1310
- ActiveModelSerializers Issue: https://github.com/rails-api/active_model_serializers/issues/1298
# Summary
Provide a consistent API for the user of the AMS.
# Motivation
The actual public API is defined under `ActiveModelSerializers`,
`ActiveModel::Serializer` and `ActiveModel`.
At the `ActiveModel::Serializer` we have:
- `ActiveModel::Serializer.config`
- `ActiveModel::Serializer`
At the `ActiveModelSerializers` we have:
- `ActiveModelSerializers::Model`
- `ActiveModelSerializers.logger`
At `ActiveModel` we have:
- `ActiveModel::SerializableResource`
The idea here is to provide a single namespace `ActiveModelSerializers` to the user.
Following the same idea we have on other gems like
[Devise](https://github.com/plataformatec/devise/blob/e9c82472ffe7c43a448945f77e034a0e47dde0bb/lib/devise.rb),
[Refile](https://github.com/refile/refile/blob/6b24c293d044862dafbf1bfa4606672a64903aa2/lib/refile.rb) and
[Active Job](https://github.com/rails/rails/blob/30bacc26f8f258b39e12f63fe52389a968d9c1ea/activejob/lib/active_job.rb)
for example.
This way we are clarifing the boundaries of
[ActiveModelSerializers and Rails](https://github.com/rails-api/active_model_serializers/blob/master/CHANGELOG.md#prehistory)
and make clear that the `ActiveModel::Serializer` class is no longer the primary
behavior of the ActiveModelSerializers.
# Detailed design
## New classes and modules organization
Since this will be a big change we can do this on baby steps, read small pull requests. A
possible approach is:
- All new code will be in `lib/active_model_serializers/` using
the module namespace `ActiveModelSerializers`.
- Move all content under `ActiveModel::Serializer` to be under
`ActiveModelSerializers`, the adapter is on this steps;
- Move all content under `ActiveModel` to be under `ActiveModelSerializers`,
the `SerializableResource` is on this step;
- Change all public API that doesn't make sense, keeping in mind only to keep
this in the same namespace
- Update the README;
- Update the docs;
The following table represents the current and the desired classes and modules
at the first moment.
| Current | Desired | Notes |
|--------------------------------------------------------|--------------------------------------------------|--------------------|
| `ActiveModelSerializers` and `ActiveModel::Serializer` | `ActiveModelSerializers` | The main namespace |
| `ActiveModelSerializers.logger` | `ActiveModelSerializers.logger` ||
| `ActiveModelSerializers::Model` | `ActiveModelSerializers::Model` ||
| `ActiveModel::SerializableResource` | `ActiveModelSerializers::SerializableResource` ||
| `ActiveModel::Serializer` | `ActiveModelSerializers::Serializer` | The name can be discussed in a future pull request. For example, we can rename this to `Resource` [following this idea](https://github.com/rails-api/active_model_serializers/pull/1301/files#r42963185) more info about naming in the next section|
| `ActiveModel::Serializer.config` | `ActiveModelSerializers.config` ||
## Renaming of class and modules
When moving some content to the new namespace we can find some names that does
not make much sense like `ActiveModel::Serializer::Adapter::JsonApi`.
Discussion of renaming existing classes / modules and JsonApi objects will
happen in separate pull requests, and issues, and in the google doc
https://docs.google.com/document/d/1rcrJr0sVcazY2Opd_6Kmv1iIwuHbI84s1P_NzFn-05c/edit?usp=sharing
Some of names already have a definition.
- Adapters get their own namespace under ActiveModelSerializers. E.g
`ActiveModelSerializers::Adapter`
- Serializers get their own namespace under ActiveModelSerializers. E.g
`ActiveModelSerializers::Serializer`
## Keeping compatibility
All moved classes or modules be aliased to their old name and location with
deprecation warnings, such as
[was done for CollectionSerializer](https://github.com/rails-api/active_model_serializers/pull/1251).
# Drawbacks
This will be a breaking change, so all users serializers will be broken after a
major bump.
All pull requests will need to rebase since the architeture will change a lot.
# Alternatives
We can keep the way it is, and keep in mind to not add another namespace as a
public API.
# Unresolved questions
What is the better class name to be used to the class that will be inherited at
the creation of a serializer. This can be discussed in other RFC or directly via
pull request.

View File

@ -1,66 +0,0 @@
require 'active_support/core_ext/class/attribute'
require 'active_model_serializers/serialization_context'
module ActionController
module Serialization
extend ActiveSupport::Concern
include ActionController::Renderers
module ClassMethods
def serialization_scope(scope)
self._serialization_scope = scope
end
end
included do
class_attribute :_serialization_scope
self._serialization_scope = :current_user
attr_writer :namespace_for_serializer
end
def namespace_for_serializer
@namespace_for_serializer ||= self.class.parent unless self.class.parent == Object
end
def serialization_scope
return unless _serialization_scope && respond_to?(_serialization_scope, true)
send(_serialization_scope)
end
def get_serializer(resource, options = {})
unless use_adapter?
warn 'ActionController::Serialization#use_adapter? has been removed. '\
"Please pass 'adapter: false' or see ActiveSupport::SerializableResource.new"
options[:adapter] = false
end
options.fetch(:namespace) { options[:namespace] = namespace_for_serializer }
serializable_resource = ActiveModelSerializers::SerializableResource.new(resource, options)
serializable_resource.serialization_scope ||= options.fetch(:scope) { serialization_scope }
serializable_resource.serialization_scope_name = options.fetch(:scope_name) { _serialization_scope }
# For compatibility with the JSON renderer: `json.to_json(options) if json.is_a?(String)`.
# Otherwise, since `serializable_resource` is not a string, the renderer would call
# `to_json` on a String and given odd results, such as `"".to_json #=> '""'`
serializable_resource.adapter.is_a?(String) ? serializable_resource.adapter : serializable_resource
end
# Deprecated
def use_adapter?
true
end
[:_render_option_json, :_render_with_renderer_json].each do |renderer_method|
define_method renderer_method do |resource, options|
options.fetch(:serialization_context) do
options[:serialization_context] = ActiveModelSerializers::SerializationContext.new(request, options)
end
serializable_resource = get_serializer(resource, options)
super(serializable_resource, options)
end
end
end
end

View File

@ -1,11 +0,0 @@
require 'set'
module ActiveModel
class SerializableResource
class << self
extend ActiveModelSerializers::Deprecate
delegate_and_deprecate :new, ActiveModelSerializers::SerializableResource
end
end
end

View File

@ -1,409 +0,0 @@
require 'thread_safe'
require 'jsonapi/include_directive'
require 'active_model/serializer/collection_serializer'
require 'active_model/serializer/array_serializer'
require 'active_model/serializer/error_serializer'
require 'active_model/serializer/errors_serializer'
require 'active_model/serializer/concerns/caching'
require 'active_model/serializer/fieldset'
require 'active_model/serializer/lint'
# ActiveModel::Serializer is an abstract class that is
# reified when subclassed to decorate a resource.
module ActiveModel
class Serializer
undef_method :select, :display # These IO methods, which are mixed into Kernel,
# sometimes conflict with attribute names. We don't need these IO methods.
# @see #serializable_hash for more details on these valid keys.
SERIALIZABLE_HASH_VALID_KEYS = [:only, :except, :methods, :include, :root].freeze
extend ActiveSupport::Autoload
autoload :Adapter
autoload :Null
autoload :Attribute
autoload :Association
autoload :Reflection
autoload :SingularReflection
autoload :CollectionReflection
autoload :BelongsToReflection
autoload :HasOneReflection
autoload :HasManyReflection
include ActiveSupport::Configurable
include Caching
# @param resource [ActiveRecord::Base, ActiveModelSerializers::Model]
# @return [ActiveModel::Serializer]
# Preferentially returns
# 1. resource.serializer_class
# 2. ArraySerializer when resource is a collection
# 3. options[:serializer]
# 4. lookup serializer when resource is a Class
def self.serializer_for(resource_or_class, options = {})
if resource_or_class.respond_to?(:serializer_class)
resource_or_class.serializer_class
elsif resource_or_class.respond_to?(:to_ary)
config.collection_serializer
else
resource_class = resource_or_class.class == Class ? resource_or_class : resource_or_class.class
options.fetch(:serializer) { get_serializer_for(resource_class, options[:namespace]) }
end
end
# @see ActiveModelSerializers::Adapter.lookup
# Deprecated
def self.adapter
ActiveModelSerializers::Adapter.lookup(config.adapter)
end
class << self
extend ActiveModelSerializers::Deprecate
deprecate :adapter, 'ActiveModelSerializers::Adapter.configured_adapter'
end
# @api private
def self.serializer_lookup_chain_for(klass, namespace = nil)
lookups = ActiveModelSerializers.config.serializer_lookup_chain
Array[*lookups].flat_map do |lookup|
lookup.call(klass, self, namespace)
end.compact
end
# Used to cache serializer name => serializer class
# when looked up by Serializer.get_serializer_for.
def self.serializers_cache
@serializers_cache ||= ThreadSafe::Cache.new
end
# @api private
# Find a serializer from a class and caches the lookup.
# Preferentially returns:
# 1. class name appended with "Serializer"
# 2. try again with superclass, if present
# 3. nil
def self.get_serializer_for(klass, namespace = nil)
return nil unless config.serializer_lookup_enabled
cache_key = ActiveSupport::Cache.expand_cache_key(klass, namespace)
serializers_cache.fetch_or_store(cache_key) do
# NOTE(beauby): When we drop 1.9.3 support we can lazify the map for perfs.
lookup_chain = serializer_lookup_chain_for(klass, namespace)
serializer_class = lookup_chain.map(&:safe_constantize).find { |x| x && x < ActiveModel::Serializer }
if serializer_class
serializer_class
elsif klass.superclass
get_serializer_for(klass.superclass)
else
nil # No serializer found
end
end
end
# @api private
def self.include_directive_from_options(options)
if options[:include_directive]
options[:include_directive]
elsif options[:include]
JSONAPI::IncludeDirective.new(options[:include], allow_wildcard: true)
else
ActiveModelSerializers.default_include_directive
end
end
# @api private
def self.serialization_adapter_instance
@serialization_adapter_instance ||= ActiveModelSerializers::Adapter::Attributes
end
# Preferred interface is ActiveModelSerializers.config
# BEGIN DEFAULT CONFIGURATION
config.collection_serializer = ActiveModel::Serializer::CollectionSerializer
config.serializer_lookup_enabled = true
# @deprecated Use {#config.collection_serializer=} instead of this. Is
# compatibility layer for ArraySerializer.
def config.array_serializer=(collection_serializer)
self.collection_serializer = collection_serializer
end
# @deprecated Use {#config.collection_serializer} instead of this. Is
# compatibility layer for ArraySerializer.
def config.array_serializer
collection_serializer
end
config.default_includes = '*'
config.adapter = :attributes
config.key_transform = nil
config.jsonapi_pagination_links_enabled = true
config.jsonapi_resource_type = :plural
config.jsonapi_namespace_separator = '-'.freeze
config.jsonapi_version = '1.0'
config.jsonapi_toplevel_meta = {}
# Make JSON API top-level jsonapi member opt-in
# ref: http://jsonapi.org/format/#document-top-level
config.jsonapi_include_toplevel_object = false
config.include_data_default = true
# For configuring how serializers are found.
# This should be an array of procs.
#
# The priority of the output is that the first item
# in the evaluated result array will take precedence
# over other possible serializer paths.
#
# i.e.: First match wins.
#
# @example output
# => [
# "CustomNamespace::ResourceSerializer",
# "ParentSerializer::ResourceSerializer",
# "ResourceNamespace::ResourceSerializer" ,
# "ResourceSerializer"]
#
# If CustomNamespace::ResourceSerializer exists, it will be used
# for serialization
config.serializer_lookup_chain = ActiveModelSerializers::LookupChain::DEFAULT.dup
config.schema_path = 'test/support/schemas'
# END DEFAULT CONFIGURATION
with_options instance_writer: false, instance_reader: false do |serializer|
serializer.class_attribute :_attributes_data # @api private
self._attributes_data ||= {}
end
with_options instance_writer: false, instance_reader: true do |serializer|
serializer.class_attribute :_reflections
self._reflections ||= {}
serializer.class_attribute :_links # @api private
self._links ||= {}
serializer.class_attribute :_meta # @api private
serializer.class_attribute :_type # @api private
end
def self.inherited(base)
super
base._attributes_data = _attributes_data.dup
base._reflections = _reflections.dup
base._links = _links.dup
end
# @return [Array<Symbol>] Key names of declared attributes
# @see Serializer::attribute
def self._attributes
_attributes_data.keys
end
# BEGIN SERIALIZER MACROS
# @example
# class AdminAuthorSerializer < ActiveModel::Serializer
# attributes :id, :name, :recent_edits
def self.attributes(*attrs)
attrs = attrs.first if attrs.first.class == Array
attrs.each do |attr|
attribute(attr)
end
end
# @example
# class AdminAuthorSerializer < ActiveModel::Serializer
# attributes :id, :recent_edits
# attribute :name, key: :title
#
# attribute :full_name do
# "#{object.first_name} #{object.last_name}"
# end
#
# def recent_edits
# object.edits.last(5)
# end
def self.attribute(attr, options = {}, &block)
key = options.fetch(:key, attr)
_attributes_data[key] = Attribute.new(attr, options, block)
end
# @param [Symbol] name of the association
# @param [Hash<Symbol => any>] options for the reflection
# @return [void]
#
# @example
# has_many :comments, serializer: CommentSummarySerializer
#
def self.has_many(name, options = {}, &block) # rubocop:disable Style/PredicateName
associate(HasManyReflection.new(name, options, block))
end
# @param [Symbol] name of the association
# @param [Hash<Symbol => any>] options for the reflection
# @return [void]
#
# @example
# belongs_to :author, serializer: AuthorSerializer
#
def self.belongs_to(name, options = {}, &block)
associate(BelongsToReflection.new(name, options, block))
end
# @param [Symbol] name of the association
# @param [Hash<Symbol => any>] options for the reflection
# @return [void]
#
# @example
# has_one :author, serializer: AuthorSerializer
#
def self.has_one(name, options = {}, &block) # rubocop:disable Style/PredicateName
associate(HasOneReflection.new(name, options, block))
end
# Add reflection and define {name} accessor.
# @param [ActiveModel::Serializer::Reflection] reflection
# @return [void]
#
# @api private
def self.associate(reflection)
key = reflection.options[:key] || reflection.name
self._reflections[key] = reflection
end
private_class_method :associate
# Define a link on a serializer.
# @example
# link(:self) { resource_url(object) }
# @example
# link(:self) { "http://example.com/resource/#{object.id}" }
# @example
# link :resource, "http://example.com/resource"
#
def self.link(name, value = nil, &block)
_links[name] = block || value
end
# Set the JSON API meta attribute of a serializer.
# @example
# class AdminAuthorSerializer < ActiveModel::Serializer
# meta { stuff: 'value' }
# @example
# meta do
# { comment_count: object.comments.count }
# end
def self.meta(value = nil, &block)
self._meta = block || value
end
# Set the JSON API type of a serializer.
# @example
# class AdminAuthorSerializer < ActiveModel::Serializer
# type 'authors'
def self.type(type)
self._type = type && type.to_s
end
# END SERIALIZER MACROS
attr_accessor :object, :root, :scope
# `scope_name` is set as :current_user by default in the controller.
# If the instance does not have a method named `scope_name`, it
# defines the method so that it calls the +scope+.
def initialize(object, options = {})
self.object = object
self.instance_options = options
self.root = instance_options[:root]
self.scope = instance_options[:scope]
return if !(scope_name = instance_options[:scope_name]) || respond_to?(scope_name)
define_singleton_method scope_name, -> { scope }
end
def success?
true
end
# Return the +attributes+ of +object+ as presented
# by the serializer.
def attributes(requested_attrs = nil, reload = false)
@attributes = nil if reload
@attributes ||= self.class._attributes_data.each_with_object({}) do |(key, attr), hash|
next if attr.excluded?(self)
next unless requested_attrs.nil? || requested_attrs.include?(key)
hash[key] = attr.value(self)
end
end
# @param [JSONAPI::IncludeDirective] include_directive (defaults to the
# +default_include_directive+ config value when not provided)
# @return [Enumerator<Association>]
def associations(include_directive = ActiveModelSerializers.default_include_directive, include_slice = nil)
include_slice ||= include_directive
return Enumerator.new unless object
Enumerator.new do |y|
self.class._reflections.each do |key, reflection|
next if reflection.excluded?(self)
next unless include_directive.key?(key)
association = reflection.build_association(self, instance_options, include_slice)
y.yield association
end
end
end
# @return [Hash] containing the attributes and first level
# associations, similar to how ActiveModel::Serializers::JSON is used
# in ActiveRecord::Base.
def serializable_hash(adapter_options = nil, options = {}, adapter_instance = self.class.serialization_adapter_instance)
adapter_options ||= {}
options[:include_directive] ||= ActiveModel::Serializer.include_directive_from_options(adapter_options)
resource = attributes_hash(adapter_options, options, adapter_instance)
relationships = associations_hash(adapter_options, options, adapter_instance)
resource.merge(relationships)
end
alias to_hash serializable_hash
alias to_h serializable_hash
# @see #serializable_hash
def as_json(adapter_opts = nil)
serializable_hash(adapter_opts)
end
# Used by adapter as resource root.
def json_key
root || _type || object.class.model_name.to_s.underscore
end
def read_attribute_for_serialization(attr)
if respond_to?(attr)
send(attr)
else
object.read_attribute_for_serialization(attr)
end
end
# @api private
def attributes_hash(_adapter_options, options, adapter_instance)
if self.class.cache_enabled?
fetch_attributes(options[:fields], options[:cached_attributes] || {}, adapter_instance)
elsif self.class.fragment_cache_enabled?
fetch_attributes_fragment(adapter_instance, options[:cached_attributes] || {})
else
attributes(options[:fields], true)
end
end
# @api private
def associations_hash(adapter_options, options, adapter_instance)
include_directive = options.fetch(:include_directive)
include_slice = options[:include_slice]
associations(include_directive, include_slice).each_with_object({}) do |association, relationships|
adapter_opts = adapter_options.merge(include_directive: include_directive[association.key], adapter_instance: adapter_instance)
relationships[association.key] = association.serializable_hash(adapter_opts, adapter_instance)
end
end
protected
attr_accessor :instance_options
end
end

View File

@ -1,24 +0,0 @@
require 'active_model_serializers/adapter'
require 'active_model_serializers/deprecate'
module ActiveModel
class Serializer
# @deprecated Use ActiveModelSerializers::Adapter instead
module Adapter
class << self
extend ActiveModelSerializers::Deprecate
DEPRECATED_METHODS = [:create, :adapter_class, :adapter_map, :adapters, :register, :lookup].freeze
DEPRECATED_METHODS.each do |method|
delegate_and_deprecate method, ActiveModelSerializers::Adapter
end
end
end
end
end
require 'active_model/serializer/adapter/base'
require 'active_model/serializer/adapter/null'
require 'active_model/serializer/adapter/attributes'
require 'active_model/serializer/adapter/json'
require 'active_model/serializer/adapter/json_api'

View File

@ -1,15 +0,0 @@
module ActiveModel
class Serializer
module Adapter
class Attributes < DelegateClass(ActiveModelSerializers::Adapter::Attributes)
def initialize(serializer, options = {})
super(ActiveModelSerializers::Adapter::Attributes.new(serializer, options))
end
class << self
extend ActiveModelSerializers::Deprecate
deprecate :new, 'ActiveModelSerializers::Adapter::Json.'
end
end
end
end
end

View File

@ -1,18 +0,0 @@
module ActiveModel
class Serializer
module Adapter
class Base < DelegateClass(ActiveModelSerializers::Adapter::Base)
class << self
extend ActiveModelSerializers::Deprecate
deprecate :inherited, 'ActiveModelSerializers::Adapter::Base.'
end
# :nocov:
def initialize(serializer, options = {})
super(ActiveModelSerializers::Adapter::Base.new(serializer, options))
end
# :nocov:
end
end
end
end

View File

@ -1,15 +0,0 @@
module ActiveModel
class Serializer
module Adapter
class Json < DelegateClass(ActiveModelSerializers::Adapter::Json)
def initialize(serializer, options = {})
super(ActiveModelSerializers::Adapter::Json.new(serializer, options))
end
class << self
extend ActiveModelSerializers::Deprecate
deprecate :new, 'ActiveModelSerializers::Adapter::Json.new'
end
end
end
end
end

View File

@ -1,15 +0,0 @@
module ActiveModel
class Serializer
module Adapter
class JsonApi < DelegateClass(ActiveModelSerializers::Adapter::JsonApi)
def initialize(serializer, options = {})
super(ActiveModelSerializers::Adapter::JsonApi.new(serializer, options))
end
class << self
extend ActiveModelSerializers::Deprecate
deprecate :new, 'ActiveModelSerializers::Adapter::JsonApi.new'
end
end
end
end
end

View File

@ -1,15 +0,0 @@
module ActiveModel
class Serializer
module Adapter
class Null < DelegateClass(ActiveModelSerializers::Adapter::Null)
def initialize(serializer, options = {})
super(ActiveModelSerializers::Adapter::Null.new(serializer, options))
end
class << self
extend ActiveModelSerializers::Deprecate
deprecate :new, 'ActiveModelSerializers::Adapter::Null.new'
end
end
end
end
end

View File

@ -1,12 +0,0 @@
require 'active_model/serializer/collection_serializer'
module ActiveModel
class Serializer
class ArraySerializer < CollectionSerializer
class << self
extend ActiveModelSerializers::Deprecate
deprecate :new, 'ActiveModel::Serializer::CollectionSerializer.'
end
end
end
end

View File

@ -1,71 +0,0 @@
require 'active_model/serializer/lazy_association'
module ActiveModel
class Serializer
# This class holds all information about serializer's association.
#
# @api private
Association = Struct.new(:reflection, :association_options) do
attr_reader :lazy_association
delegate :object, :include_data?, :virtual_value, :collection?, to: :lazy_association
def initialize(*)
super
@lazy_association = LazyAssociation.new(reflection, association_options)
end
# @return [Symbol]
delegate :name, to: :reflection
# @return [Symbol]
def key
reflection_options.fetch(:key, name)
end
# @return [True,False]
def key?
reflection_options.key?(:key)
end
# @return [Hash]
def links
reflection_options.fetch(:links) || {}
end
# @return [Hash, nil]
# This gets mutated, so cannot use the cached reflection_options
def meta
reflection.options[:meta]
end
def belongs_to?
reflection.foreign_key_on == :self
end
def polymorphic?
true == reflection_options[:polymorphic]
end
# @api private
def serializable_hash(adapter_options, adapter_instance)
association_serializer = lazy_association.serializer
return virtual_value if virtual_value
association_object = association_serializer && association_serializer.object
return unless association_object
serialization = association_serializer.serializable_hash(adapter_options, {}, adapter_instance)
if polymorphic? && serialization
polymorphic_type = association_object.class.name.underscore
serialization = { type: polymorphic_type, polymorphic_type.to_sym => serialization }
end
serialization
end
private
delegate :reflection_options, to: :lazy_association
end
end
end

View File

@ -1,25 +0,0 @@
require 'active_model/serializer/field'
module ActiveModel
class Serializer
# Holds all the meta-data about an attribute as it was specified in the
# ActiveModel::Serializer class.
#
# @example
# class PostSerializer < ActiveModel::Serializer
# attribute :content
# attribute :name, key: :title
# attribute :email, key: :author_email, if: :user_logged_in?
# attribute :preview do
# truncate(object.content)
# end
#
# def user_logged_in?
# current_user.logged_in?
# end
# end
#
class Attribute < Field
end
end
end

View File

@ -1,11 +0,0 @@
module ActiveModel
class Serializer
# @api private
class BelongsToReflection < Reflection
# @api private
def foreign_key_on
:self
end
end
end
end

View File

@ -1,87 +0,0 @@
module ActiveModel
class Serializer
class CollectionSerializer
include Enumerable
delegate :each, to: :@serializers
attr_reader :object, :root
def initialize(resources, options = {})
@object = resources
@options = options
@root = options[:root]
@serializers = serializers_from_resources
end
def success?
true
end
# @api private
def serializable_hash(adapter_options, options, adapter_instance)
include_directive = ActiveModel::Serializer.include_directive_from_options(adapter_options)
adapter_options[:cached_attributes] ||= ActiveModel::Serializer.cache_read_multi(self, adapter_instance, include_directive)
adapter_opts = adapter_options.merge(include_directive: include_directive)
serializers.map do |serializer|
serializer.serializable_hash(adapter_opts, options, adapter_instance)
end
end
# TODO: unify naming of root, json_key, and _type. Right now, a serializer's
# json_key comes from the root option or the object's model name, by default.
# But, if a dev defines a custom `json_key` method with an explicit value,
# we have no simple way to know that it is safe to call that instance method.
# (which is really a class property at this point, anyhow).
# rubocop:disable Metrics/CyclomaticComplexity
# Disabling cop since it's good to highlight the complexity of this method by
# including all the logic right here.
def json_key
return root if root
# 1. get from options[:serializer] for empty resource collection
key = object.empty? &&
(explicit_serializer_class = options[:serializer]) &&
explicit_serializer_class._type
# 2. get from first serializer instance in collection
key ||= (serializer = serializers.first) && serializer.json_key
# 3. get from collection name, if a named collection
key ||= object.respond_to?(:name) ? object.name && object.name.underscore : nil
# 4. key may be nil for empty collection and no serializer option
key && key.pluralize
end
# rubocop:enable Metrics/CyclomaticComplexity
def paginated?
ActiveModelSerializers.config.jsonapi_pagination_links_enabled &&
object.respond_to?(:current_page) &&
object.respond_to?(:total_pages) &&
object.respond_to?(:size)
end
protected
attr_reader :serializers, :options
private
def serializers_from_resources
serializer_context_class = options.fetch(:serializer_context_class, ActiveModel::Serializer)
object.map do |resource|
serializer_from_resource(resource, serializer_context_class, options)
end
end
def serializer_from_resource(resource, serializer_context_class, options)
serializer_class = options.fetch(:serializer) do
serializer_context_class.serializer_for(resource, namespace: options[:namespace])
end
if serializer_class.nil?
ActiveModelSerializers.logger.debug "No serializer found for resource: #{resource.inspect}"
throw :no_serializer
else
serializer_class.new(resource, options.except(:serializer))
end
end
end
end
end

View File

@ -1,300 +0,0 @@
module ActiveModel
class Serializer
UndefinedCacheKey = Class.new(StandardError)
module Caching
extend ActiveSupport::Concern
included do
with_options instance_writer: false, instance_reader: false do |serializer|
serializer.class_attribute :_cache # @api private : the cache store
serializer.class_attribute :_cache_key # @api private : when present, is first item in cache_key. Ignored if the serializable object defines #cache_key.
serializer.class_attribute :_cache_only # @api private : when fragment caching, whitelists fetch_attributes. Cannot combine with except
serializer.class_attribute :_cache_except # @api private : when fragment caching, blacklists fetch_attributes. Cannot combine with only
serializer.class_attribute :_cache_options # @api private : used by CachedSerializer, passed to _cache.fetch
# _cache_options include:
# expires_in
# compress
# force
# race_condition_ttl
# Passed to ::_cache as
# serializer.cache_store.fetch(cache_key, @klass._cache_options)
# Passed as second argument to serializer.cache_store.fetch(cache_key, serializer_class._cache_options)
serializer.class_attribute :_cache_digest_file_path # @api private : Derived at inheritance
end
end
# Matches
# "c:/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb:1:in `<top (required)>'"
# AND
# "/c/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb:1:in `<top (required)>'"
# AS
# c/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb
CALLER_FILE = /
\A # start of string
.+ # file path (one or more characters)
(?= # stop previous match when
:\d+ # a colon is followed by one or more digits
:in # followed by a colon followed by in
)
/x
module ClassMethods
def inherited(base)
caller_line = caller[1]
base._cache_digest_file_path = caller_line
super
end
def _cache_digest
return @_cache_digest if defined?(@_cache_digest)
@_cache_digest = digest_caller_file(_cache_digest_file_path)
end
# Hashes contents of file for +_cache_digest+
def digest_caller_file(caller_line)
serializer_file_path = caller_line[CALLER_FILE]
serializer_file_contents = IO.read(serializer_file_path)
Digest::MD5.hexdigest(serializer_file_contents)
rescue TypeError, Errno::ENOENT
warn <<-EOF.strip_heredoc
Cannot digest non-existent file: '#{caller_line}'.
Please set `::_cache_digest` of the serializer
if you'd like to cache it.
EOF
''.freeze
end
def _skip_digest?
_cache_options && _cache_options[:skip_digest]
end
# @api private
# maps attribute value to explicit key name
# @see Serializer::attribute
# @see Serializer::fragmented_attributes
def _attributes_keys
_attributes_data
.each_with_object({}) do |(key, attr), hash|
next if key == attr.name
hash[attr.name] = { key: key }
end
end
def fragmented_attributes
cached = _cache_only ? _cache_only : _attributes - _cache_except
cached = cached.map! { |field| _attributes_keys.fetch(field, field) }
non_cached = _attributes - cached
non_cached = non_cached.map! { |field| _attributes_keys.fetch(field, field) }
{
cached: cached,
non_cached: non_cached
}
end
# Enables a serializer to be automatically cached
#
# Sets +::_cache+ object to <tt>ActionController::Base.cache_store</tt>
# when Rails.configuration.action_controller.perform_caching
#
# @param options [Hash] with valid keys:
# cache_store : @see ::_cache
# key : @see ::_cache_key
# only : @see ::_cache_only
# except : @see ::_cache_except
# skip_digest : does not include digest in cache_key
# all else : @see ::_cache_options
#
# @example
# class PostSerializer < ActiveModel::Serializer
# cache key: 'post', expires_in: 3.hours
# attributes :title, :body
#
# has_many :comments
# end
#
# @todo require less code comments. See
# https://github.com/rails-api/active_model_serializers/pull/1249#issuecomment-146567837
def cache(options = {})
self._cache =
options.delete(:cache_store) ||
ActiveModelSerializers.config.cache_store ||
ActiveSupport::Cache.lookup_store(:null_store)
self._cache_key = options.delete(:key)
self._cache_only = options.delete(:only)
self._cache_except = options.delete(:except)
self._cache_options = options.empty? ? nil : options
end
# Value is from ActiveModelSerializers.config.perform_caching. Is used to
# globally enable or disable all serializer caching, just like
# Rails.configuration.action_controller.perform_caching, which is its
# default value in a Rails application.
# @return [true, false]
# Memoizes value of config first time it is called with a non-nil value.
# rubocop:disable Style/ClassVars
def perform_caching
return @@perform_caching if defined?(@@perform_caching) && !@@perform_caching.nil?
@@perform_caching = ActiveModelSerializers.config.perform_caching
end
alias perform_caching? perform_caching
# rubocop:enable Style/ClassVars
# The canonical method for getting the cache store for the serializer.
#
# @return [nil] when _cache is not set (i.e. when `cache` has not been called)
# @return [._cache] when _cache is not the NullStore
# @return [ActiveModelSerializers.config.cache_store] when _cache is the NullStore.
# This is so we can use `cache` being called to mean the serializer should be cached
# even if ActiveModelSerializers.config.cache_store has not yet been set.
# That means that when _cache is the NullStore and ActiveModelSerializers.config.cache_store
# is configured, `cache_store` becomes `ActiveModelSerializers.config.cache_store`.
# @return [nil] when _cache is the NullStore and ActiveModelSerializers.config.cache_store is nil.
def cache_store
return nil if _cache.nil?
return _cache if _cache.class != ActiveSupport::Cache::NullStore
if ActiveModelSerializers.config.cache_store
self._cache = ActiveModelSerializers.config.cache_store
else
nil
end
end
def cache_enabled?
perform_caching? && cache_store && !_cache_only && !_cache_except
end
def fragment_cache_enabled?
perform_caching? && cache_store &&
(_cache_only && !_cache_except || !_cache_only && _cache_except)
end
# Read cache from cache_store
# @return [Hash]
# Used in CollectionSerializer to set :cached_attributes
def cache_read_multi(collection_serializer, adapter_instance, include_directive)
return {} if ActiveModelSerializers.config.cache_store.blank?
keys = object_cache_keys(collection_serializer, adapter_instance, include_directive)
return {} if keys.blank?
ActiveModelSerializers.config.cache_store.read_multi(*keys)
end
# Find all cache_key for the collection_serializer
# @param serializers [ActiveModel::Serializer::CollectionSerializer]
# @param adapter_instance [ActiveModelSerializers::Adapter::Base]
# @param include_directive [JSONAPI::IncludeDirective]
# @return [Array] all cache_key of collection_serializer
def object_cache_keys(collection_serializer, adapter_instance, include_directive)
cache_keys = []
collection_serializer.each do |serializer|
cache_keys << object_cache_key(serializer, adapter_instance)
serializer.associations(include_directive).each do |association|
# TODO(BF): Process relationship without evaluating lazy_association
association_serializer = association.lazy_association.serializer
if association_serializer.respond_to?(:each)
association_serializer.each do |sub_serializer|
cache_keys << object_cache_key(sub_serializer, adapter_instance)
end
else
cache_keys << object_cache_key(association_serializer, adapter_instance)
end
end
end
cache_keys.compact.uniq
end
# @return [String, nil] the cache_key of the serializer or nil
def object_cache_key(serializer, adapter_instance)
return unless serializer.present? && serializer.object.present?
(serializer.class.cache_enabled? || serializer.class.fragment_cache_enabled?) ? serializer.cache_key(adapter_instance) : nil
end
end
### INSTANCE METHODS
def fetch_attributes(fields, cached_attributes, adapter_instance)
key = cache_key(adapter_instance)
cached_attributes.fetch(key) do
fetch(adapter_instance, serializer_class._cache_options, key) do
attributes(fields, true)
end
end
end
def fetch(adapter_instance, cache_options = serializer_class._cache_options, key = nil)
if serializer_class.cache_store
key ||= cache_key(adapter_instance)
serializer_class.cache_store.fetch(key, cache_options) do
yield
end
else
yield
end
end
# 1. Determine cached fields from serializer class options
# 2. Get non_cached_fields and fetch cache_fields
# 3. Merge the two hashes using adapter_instance#fragment_cache
def fetch_attributes_fragment(adapter_instance, cached_attributes = {})
serializer_class._cache_options ||= {}
serializer_class._cache_options[:key] = serializer_class._cache_key if serializer_class._cache_key
fields = serializer_class.fragmented_attributes
non_cached_fields = fields[:non_cached].dup
non_cached_hash = attributes(non_cached_fields, true)
include_directive = JSONAPI::IncludeDirective.new(non_cached_fields - non_cached_hash.keys)
non_cached_hash.merge! associations_hash({}, { include_directive: include_directive }, adapter_instance)
cached_fields = fields[:cached].dup
key = cache_key(adapter_instance)
cached_hash =
cached_attributes.fetch(key) do
fetch(adapter_instance, serializer_class._cache_options, key) do
hash = attributes(cached_fields, true)
include_directive = JSONAPI::IncludeDirective.new(cached_fields - hash.keys)
hash.merge! associations_hash({}, { include_directive: include_directive }, adapter_instance)
end
end
# Merge both results
adapter_instance.fragment_cache(cached_hash, non_cached_hash)
end
def cache_key(adapter_instance)
return @cache_key if defined?(@cache_key)
parts = []
parts << object_cache_key
parts << adapter_instance.cache_key
parts << serializer_class._cache_digest unless serializer_class._skip_digest?
@cache_key = expand_cache_key(parts)
end
def expand_cache_key(parts)
ActiveSupport::Cache.expand_cache_key(parts)
end
# Use object's cache_key if available, else derive a key from the object
# Pass the `key` option to the `cache` declaration or override this method to customize the cache key
def object_cache_key
if object.respond_to?(:cache_key)
object.cache_key
elsif (serializer_cache_key = (serializer_class._cache_key || serializer_class._cache_options[:key]))
object_time_safe = object.updated_at
object_time_safe = object_time_safe.strftime('%Y%m%d%H%M%S%9N') if object_time_safe.respond_to?(:strftime)
"#{serializer_cache_key}/#{object.id}-#{object_time_safe}"
else
fail UndefinedCacheKey, "#{object.class} must define #cache_key, or the 'key:' option must be passed into '#{serializer_class}.cache'"
end
end
def serializer_class
@serializer_class ||= self.class
end
end
end
end

View File

@ -1,14 +0,0 @@
module ActiveModel
class Serializer
class ErrorSerializer < ActiveModel::Serializer
# @return [Hash<field_name,Array<error_message>>]
def as_json
object.errors.messages
end
def success?
false
end
end
end
end

View File

@ -1,32 +0,0 @@
require 'active_model/serializer/error_serializer'
module ActiveModel
class Serializer
class ErrorsSerializer
include Enumerable
delegate :each, to: :@serializers
attr_reader :object, :root
def initialize(resources, options = {})
@root = options[:root]
@object = resources
@serializers = resources.map do |resource|
serializer_class = options.fetch(:serializer) { ActiveModel::Serializer::ErrorSerializer }
serializer_class.new(resource, options.except(:serializer))
end
end
def success?
false
end
def json_key
nil
end
protected
attr_reader :serializers
end
end
end

View File

@ -1,90 +0,0 @@
module ActiveModel
class Serializer
# Holds all the meta-data about a field (i.e. attribute or association) as it was
# specified in the ActiveModel::Serializer class.
# Notice that the field block is evaluated in the context of the serializer.
Field = Struct.new(:name, :options, :block) do
def initialize(*)
super
validate_condition!
end
# Compute the actual value of a field for a given serializer instance.
# @param [Serializer] The serializer instance for which the value is computed.
# @return [Object] value
#
# @api private
#
def value(serializer)
if block
serializer.instance_eval(&block)
else
serializer.read_attribute_for_serialization(name)
end
end
# Decide whether the field should be serialized by the given serializer instance.
# @param [Serializer] The serializer instance
# @return [Bool]
#
# @api private
#
def excluded?(serializer)
case condition_type
when :if
!evaluate_condition(serializer)
when :unless
evaluate_condition(serializer)
else
false
end
end
private
def validate_condition!
return if condition_type == :none
case condition
when Symbol, String, Proc
# noop
else
fail TypeError, "#{condition_type.inspect} should be a Symbol, String or Proc"
end
end
def evaluate_condition(serializer)
case condition
when Symbol
serializer.public_send(condition)
when String
serializer.instance_eval(condition)
when Proc
if condition.arity.zero?
serializer.instance_exec(&condition)
else
serializer.instance_exec(serializer, &condition)
end
else
nil
end
end
def condition_type
@condition_type ||=
if options.key?(:if)
:if
elsif options.key?(:unless)
:unless
else
:none
end
end
def condition
options[condition_type]
end
end
end
end

View File

@ -1,31 +0,0 @@
module ActiveModel
class Serializer
class Fieldset
def initialize(fields)
@raw_fields = fields || {}
end
def fields
@fields ||= parsed_fields
end
def fields_for(type)
fields[type.singularize.to_sym] || fields[type.pluralize.to_sym]
end
protected
attr_reader :raw_fields
private
def parsed_fields
if raw_fields.is_a?(Hash)
raw_fields.each_with_object({}) { |(k, v), h| h[k.to_sym] = v.map(&:to_sym) }
else
{}
end
end
end
end
end

View File

@ -1,10 +0,0 @@
module ActiveModel
class Serializer
# @api private
class HasManyReflection < Reflection
def collection?
true
end
end
end
end

View File

@ -1,7 +0,0 @@
module ActiveModel
class Serializer
# @api private
class HasOneReflection < Reflection
end
end
end

View File

@ -1,95 +0,0 @@
module ActiveModel
class Serializer
# @api private
LazyAssociation = Struct.new(:reflection, :association_options) do
REFLECTION_OPTIONS = %i(key links polymorphic meta serializer virtual_value namespace).freeze
delegate :collection?, to: :reflection
def reflection_options
@reflection_options ||= reflection.options.dup.reject { |k, _| !REFLECTION_OPTIONS.include?(k) }
end
def object
@object ||= reflection.value(
association_options.fetch(:parent_serializer),
association_options.fetch(:include_slice)
)
end
alias_method :eval_reflection_block, :object
def include_data?
eval_reflection_block if reflection.block
reflection.include_data?(
association_options.fetch(:include_slice)
)
end
# @return [ActiveModel::Serializer, nil]
def serializer
return @serializer if defined?(@serializer)
if serializer_class
serialize_object!(object)
elsif !object.nil? && !object.instance_of?(Object)
cached_result[:virtual_value] = object
end
@serializer = cached_result[:serializer]
end
def virtual_value
cached_result[:virtual_value] || reflection_options[:virtual_value]
end
def serializer_class
return @serializer_class if defined?(@serializer_class)
serializer_for_options = { namespace: namespace }
serializer_for_options[:serializer] = reflection_options[:serializer] if reflection_options.key?(:serializer)
@serializer_class = association_options.fetch(:parent_serializer).class.serializer_for(object, serializer_for_options)
end
private
def cached_result
@cached_result ||= {}
end
def serialize_object!(object)
if collection?
if (serializer = instantiate_collection_serializer(object)).nil?
# BUG: per #2027, JSON API resource relationships are only id and type, and hence either
# *require* a serializer or we need to be a little clever about figuring out the id/type.
# In either case, returning the raw virtual value will almost always be incorrect.
#
# Should be reflection_options[:virtual_value] or adapter needs to figure out what to do
# with an object that is non-nil and has no defined serializer.
cached_result[:virtual_value] = object.try(:as_json) || object
else
cached_result[:serializer] = serializer
end
else
cached_result[:serializer] = instantiate_serializer(object)
end
end
def instantiate_serializer(object)
serializer_options = association_options.fetch(:parent_serializer_options).except(:serializer)
serializer_options[:serializer_context_class] = association_options.fetch(:parent_serializer).class
serializer = reflection_options.fetch(:serializer, nil)
serializer_options[:serializer] = serializer if serializer
serializer_class.new(object, serializer_options)
end
def instantiate_collection_serializer(object)
serializer = catch(:no_serializer) do
instantiate_serializer(object)
end
serializer
end
def namespace
reflection_options[:namespace] ||
association_options.fetch(:parent_serializer_options)[:namespace]
end
end
end
end

View File

@ -1,150 +0,0 @@
module ActiveModel
class Serializer
module Lint
# == Active \Model \Serializer \Lint \Tests
#
# You can test whether an object is compliant with the Active \Model \Serializers
# API by including <tt>ActiveModel::Serializer::Lint::Tests</tt> in your TestCase.
# It will include tests that tell you whether your object is fully compliant,
# or if not, which aspects of the API are not implemented.
#
# Note an object is not required to implement all APIs in order to work
# with Active \Model \Serializers. This module only intends to provide guidance in case
# you want all features out of the box.
#
# These tests do not attempt to determine the semantic correctness of the
# returned values. For instance, you could implement <tt>serializable_hash</tt> to
# always return +{}+, and the tests would pass. It is up to you to ensure
# that the values are semantically meaningful.
module Tests
# Passes if the object responds to <tt>serializable_hash</tt> and if it takes
# zero or one arguments.
# Fails otherwise.
#
# <tt>serializable_hash</tt> returns a hash representation of a object's attributes.
# Typically, it is implemented by including ActiveModel::Serialization.
def test_serializable_hash
assert_respond_to resource, :serializable_hash, 'The resource should respond to serializable_hash'
resource.serializable_hash
resource.serializable_hash(nil)
end
# Passes if the object responds to <tt>read_attribute_for_serialization</tt>
# and if it requires one argument (the attribute to be read).
# Fails otherwise.
#
# <tt>read_attribute_for_serialization</tt> gets the attribute value for serialization
# Typically, it is implemented by including ActiveModel::Serialization.
def test_read_attribute_for_serialization
assert_respond_to resource, :read_attribute_for_serialization, 'The resource should respond to read_attribute_for_serialization'
actual_arity = resource.method(:read_attribute_for_serialization).arity
# using absolute value since arity is:
# 1 for def read_attribute_for_serialization(name); end
# -1 for alias :read_attribute_for_serialization :send
assert_equal 1, actual_arity.abs, "expected #{actual_arity.inspect}.abs to be 1 or -1"
end
# Passes if the object responds to <tt>as_json</tt> and if it takes
# zero or one arguments.
# Fails otherwise.
#
# <tt>as_json</tt> returns a hash representation of a serialized object.
# It may delegate to <tt>serializable_hash</tt>
# Typically, it is implemented either by including ActiveModel::Serialization
# which includes ActiveModel::Serializers::JSON.
# or by the JSON gem when required.
def test_as_json
assert_respond_to resource, :as_json
resource.as_json
resource.as_json(nil)
end
# Passes if the object responds to <tt>to_json</tt> and if it takes
# zero or one arguments.
# Fails otherwise.
#
# <tt>to_json</tt> returns a string representation (JSON) of a serialized object.
# It may be called on the result of <tt>as_json</tt>.
# Typically, it is implemented on all objects when the JSON gem is required.
def test_to_json
assert_respond_to resource, :to_json
resource.to_json
resource.to_json(nil)
end
# Passes if the object responds to <tt>cache_key</tt>
# Fails otherwise.
#
# <tt>cache_key</tt> returns a (self-expiring) unique key for the object,
# and is part of the (self-expiring) cache_key, which is used by the
# adapter. It is not required unless caching is enabled.
def test_cache_key
assert_respond_to resource, :cache_key
actual_arity = resource.method(:cache_key).arity
assert_includes [-1, 0], actual_arity, "expected #{actual_arity.inspect} to be 0 or -1"
end
# Passes if the object responds to <tt>updated_at</tt> and if it takes no
# arguments.
# Fails otherwise.
#
# <tt>updated_at</tt> returns a Time object or iso8601 string and
# is part of the (self-expiring) cache_key, which is used by the adapter.
# It is not required unless caching is enabled.
def test_updated_at
assert_respond_to resource, :updated_at
actual_arity = resource.method(:updated_at).arity
assert_equal 0, actual_arity
end
# Passes if the object responds to <tt>id</tt> and if it takes no
# arguments.
# Fails otherwise.
#
# <tt>id</tt> returns a unique identifier for the object.
# It is not required unless caching is enabled.
def test_id
assert_respond_to resource, :id
assert_equal 0, resource.method(:id).arity
end
# Passes if the object's class responds to <tt>model_name</tt> and if it
# is in an instance of +ActiveModel::Name+.
# Fails otherwise.
#
# <tt>model_name</tt> returns an ActiveModel::Name instance.
# It is used by the serializer to identify the object's type.
# It is not required unless caching is enabled.
def test_model_name
resource_class = resource.class
assert_respond_to resource_class, :model_name
assert_instance_of resource_class.model_name, ActiveModel::Name
end
def test_active_model_errors
assert_respond_to resource, :errors
end
def test_active_model_errors_human_attribute_name
assert_respond_to resource.class, :human_attribute_name
assert_equal(-2, resource.class.method(:human_attribute_name).arity)
end
def test_active_model_errors_lookup_ancestors
assert_respond_to resource.class, :lookup_ancestors
assert_equal 0, resource.class.method(:lookup_ancestors).arity
end
private
def resource
@resource or fail "'@resource' must be set as the linted object"
end
def assert_instance_of(result, name)
assert result.instance_of?(name), "#{result} should be an instance of #{name}"
end
end
end
end
end

View File

@ -1,17 +0,0 @@
module ActiveModel
class Serializer
class Null < Serializer
def attributes(*)
{}
end
def associations(*)
{}
end
def serializable_hash(*)
{}
end
end
end
end

View File

@ -1,207 +0,0 @@
require 'active_model/serializer/field'
require 'active_model/serializer/association'
module ActiveModel
class Serializer
# Holds all the meta-data about an association as it was specified in the
# ActiveModel::Serializer class.
#
# @example
# class PostSerializer < ActiveModel::Serializer
# has_one :author, serializer: AuthorSerializer
# belongs_to :boss, type: :users, foreign_key: :boss_id
# has_many :comments
# has_many :comments, key: :last_comments do
# object.comments.last(1)
# end
# has_many :secret_meta_data, if: :is_admin?
#
# has_one :blog do |serializer|
# meta count: object.roles.count
# serializer.cached_blog
# end
#
# private
#
# def cached_blog
# cache_store.fetch("cached_blog:#{object.updated_at}") do
# Blog.find(object.blog_id)
# end
# end
#
# def is_admin?
# current_user.admin?
# end
# end
#
# Specifically, the association 'comments' is evaluated two different ways:
# 1) as 'comments' and named 'comments'.
# 2) as 'object.comments.last(1)' and named 'last_comments'.
#
# PostSerializer._reflections # =>
# # {
# # author: HasOneReflection.new(:author, serializer: AuthorSerializer),
# # comments: HasManyReflection.new(:comments)
# # last_comments: HasManyReflection.new(:comments, { key: :last_comments }, #<Block>)
# # secret_meta_data: HasManyReflection.new(:secret_meta_data, { if: :is_admin? })
# # }
#
# So you can inspect reflections in your Adapters.
class Reflection < Field
attr_reader :foreign_key, :type
def initialize(*)
super
options[:links] = {}
options[:include_data_setting] = Serializer.config.include_data_default
options[:meta] = nil
@type = options.fetch(:type) do
class_name = options.fetch(:class_name, name.to_s.camelize.singularize)
class_name.underscore.pluralize.to_sym
end
@foreign_key = options.fetch(:foreign_key) do
if collection?
"#{name.to_s.singularize}_ids".to_sym
else
"#{name}_id".to_sym
end
end
end
# @api public
# @example
# has_one :blog do
# include_data false
# link :self, 'a link'
# link :related, 'another link'
# link :self, '//example.com/link_author/relationships/bio'
# id = object.profile.id
# link :related do
# "//example.com/profiles/#{id}" if id != 123
# end
# link :related do
# ids = object.likes.map(&:id).join(',')
# href "//example.com/likes/#{ids}"
# meta ids: ids
# end
# end
def link(name, value = nil)
options[:links][name] = block_given? ? Proc.new : value
:nil
end
# @api public
# @example
# has_one :blog do
# include_data false
# meta(id: object.blog.id)
# meta liked: object.likes.any?
# link :self do
# href object.blog.id.to_s
# meta(id: object.blog.id)
# end
def meta(value = nil)
options[:meta] = block_given? ? Proc.new : value
:nil
end
# @api public
# @example
# has_one :blog do
# include_data false
# link :self, 'a link'
# link :related, 'another link'
# end
#
# has_one :blog do
# include_data false
# link :self, 'a link'
# link :related, 'another link'
# end
#
# belongs_to :reviewer do
# meta name: 'Dan Brown'
# include_data true
# end
#
# has_many :tags, serializer: TagSerializer do
# link :self, '//example.com/link_author/relationships/tags'
# include_data :if_sideloaded
# end
def include_data(value = true)
options[:include_data_setting] = value
:nil
end
def collection?
false
end
def include_data?(include_slice)
include_data_setting = options[:include_data_setting]
case include_data_setting
when :if_sideloaded then include_slice.key?(name)
when true then true
when false then false
else fail ArgumentError, "Unknown include_data_setting '#{include_data_setting.inspect}'"
end
end
# @param serializer [ActiveModel::Serializer]
# @yield [ActiveModel::Serializer]
# @return [:nil, associated resource or resource collection]
def value(serializer, include_slice)
@object = serializer.object
@scope = serializer.scope
block_value = instance_exec(serializer, &block) if block
return unless include_data?(include_slice)
if block && block_value != :nil
block_value
else
serializer.read_attribute_for_serialization(name)
end
end
# @api private
def foreign_key_on
:related
end
# Build association. This method is used internally to
# build serializer's association by its reflection.
#
# @param [Serializer] parent_serializer for given association
# @param [Hash{Symbol => Object}] parent_serializer_options
#
# @example
# # Given the following serializer defined:
# class PostSerializer < ActiveModel::Serializer
# has_many :comments, serializer: CommentSummarySerializer
# end
#
# # Then you instantiate your serializer
# post_serializer = PostSerializer.new(post, foo: 'bar') #
# # to build association for comments you need to get reflection
# comments_reflection = PostSerializer._reflections.detect { |r| r.name == :comments }
# # and #build_association
# comments_reflection.build_association(post_serializer, foo: 'bar')
#
# @api private
def build_association(parent_serializer, parent_serializer_options, include_slice = {})
association_options = {
parent_serializer: parent_serializer,
parent_serializer_options: parent_serializer_options,
include_slice: include_slice
}
Association.new(self, association_options)
end
protected
# used in instance exec
attr_accessor :object, :scope
end
end
end

View File

@ -1,5 +0,0 @@
module ActiveModel
class Serializer
VERSION = '0.10.6'.freeze
end
end

View File

@ -1,53 +0,0 @@
require 'active_model'
require 'active_support'
require 'active_support/core_ext/object/with_options'
require 'active_support/core_ext/string/inflections'
require 'active_support/json'
module ActiveModelSerializers
extend ActiveSupport::Autoload
autoload :Model
autoload :Callbacks
autoload :Deserialization
autoload :SerializableResource
autoload :Logging
autoload :Test
autoload :Adapter
autoload :JsonPointer
autoload :Deprecate
autoload :LookupChain
class << self; attr_accessor :logger; end
self.logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDOUT))
def self.config
ActiveModel::Serializer.config
end
# The file name and line number of the caller of the caller of this method.
def self.location_of_caller
caller[1] =~ /(.*?):(\d+).*?$/i
file = Regexp.last_match(1)
lineno = Regexp.last_match(2).to_i
[file, lineno]
end
# Memoized default include directive
# @return [JSONAPI::IncludeDirective]
def self.default_include_directive
@default_include_directive ||= JSONAPI::IncludeDirective.new(config.default_includes, allow_wildcard: true)
end
def self.silence_warnings
original_verbose = $VERBOSE
$VERBOSE = nil
yield
ensure
$VERBOSE = original_verbose
end
require 'active_model/serializer/version'
require 'active_model/serializer'
require 'active_model/serializable_resource'
require 'active_model_serializers/railtie' if defined?(::Rails)
end

View File

@ -1,98 +0,0 @@
module ActiveModelSerializers
module Adapter
UnknownAdapterError = Class.new(ArgumentError)
ADAPTER_MAP = {} # rubocop:disable Style/MutableConstant
private_constant :ADAPTER_MAP if defined?(private_constant)
class << self # All methods are class functions
# :nocov:
def new(*args)
fail ArgumentError, 'Adapters inherit from Adapter::Base.' \
"Adapter.new called with args: '#{args.inspect}', from" \
"'caller[0]'."
end
# :nocov:
def configured_adapter
lookup(ActiveModelSerializers.config.adapter)
end
def create(resource, options = {})
override = options.delete(:adapter)
klass = override ? adapter_class(override) : configured_adapter
klass.new(resource, options)
end
# @see ActiveModelSerializers::Adapter.lookup
def adapter_class(adapter)
ActiveModelSerializers::Adapter.lookup(adapter)
end
# @return [Hash<adapter_name, adapter_class>]
def adapter_map
ADAPTER_MAP
end
# @return [Array<Symbol>] list of adapter names
def adapters
adapter_map.keys.sort
end
# Adds an adapter 'klass' with 'name' to the 'adapter_map'
# Names are stringified and underscored
# @param name [Symbol, String, Class] name of the registered adapter
# @param klass [Class] adapter class itself, optional if name is the class
# @example
# AMS::Adapter.register(:my_adapter, MyAdapter)
# @note The registered name strips out 'ActiveModelSerializers::Adapter::'
# so that registering 'ActiveModelSerializers::Adapter::Json' and
# 'Json' will both register as 'json'.
def register(name, klass = name)
name = name.to_s.gsub(/\AActiveModelSerializers::Adapter::/, ''.freeze)
adapter_map[name.underscore] = klass
self
end
def registered_name(adapter_class)
ADAPTER_MAP.key adapter_class
end
# @param adapter [String, Symbol, Class] name to fetch adapter by
# @return [ActiveModelSerializers::Adapter] subclass of Adapter
# @raise [UnknownAdapterError]
def lookup(adapter)
# 1. return if is a class
return adapter if adapter.is_a?(Class)
adapter_name = adapter.to_s.underscore
# 2. return if registered
adapter_map.fetch(adapter_name) do
# 3. try to find adapter class from environment
adapter_class = find_by_name(adapter_name)
register(adapter_name, adapter_class)
adapter_class
end
rescue NameError, ArgumentError => e
failure_message =
"NameError: #{e.message}. Unknown adapter: #{adapter.inspect}. Valid adapters are: #{adapters}"
raise UnknownAdapterError, failure_message, e.backtrace
end
# @api private
def find_by_name(adapter_name)
adapter_name = adapter_name.to_s.classify.tr('API', 'Api')
"ActiveModelSerializers::Adapter::#{adapter_name}".safe_constantize ||
"ActiveModelSerializers::Adapter::#{adapter_name.pluralize}".safe_constantize or # rubocop:disable Style/AndOr
fail UnknownAdapterError
end
private :find_by_name
end
# Gotta be at the bottom to use the code above it :(
extend ActiveSupport::Autoload
autoload :Base
autoload :Null
autoload :Attributes
autoload :Json
autoload :JsonApi
end
end

View File

@ -1,13 +0,0 @@
module ActiveModelSerializers
module Adapter
class Attributes < Base
def serializable_hash(options = nil)
options = serialization_options(options)
options[:fields] ||= instance_options[:fields]
serialized_hash = serializer.serializable_hash(instance_options, options, self)
self.class.transform_key_casing!(serialized_hash, instance_options)
end
end
end
end

View File

@ -1,83 +0,0 @@
require 'case_transform'
module ActiveModelSerializers
module Adapter
class Base
# Automatically register adapters when subclassing
def self.inherited(subclass)
ActiveModelSerializers::Adapter.register(subclass)
end
# Sets the default transform for the adapter.
#
# @return [Symbol] the default transform for the adapter
def self.default_key_transform
:unaltered
end
# Determines the transform to use in order of precedence:
# adapter option, global config, adapter default.
#
# @param options [Object]
# @return [Symbol] the transform to use
def self.transform(options)
return options[:key_transform] if options && options[:key_transform]
ActiveModelSerializers.config.key_transform || default_key_transform
end
# Transforms the casing of the supplied value.
#
# @param value [Object] the value to be transformed
# @param options [Object] serializable resource options
# @return [Symbol] the default transform for the adapter
def self.transform_key_casing!(value, options)
CaseTransform.send(transform(options), value)
end
def self.cache_key
@cache_key ||= ActiveModelSerializers::Adapter.registered_name(self)
end
def self.fragment_cache(cached_hash, non_cached_hash)
non_cached_hash.merge cached_hash
end
attr_reader :serializer, :instance_options
def initialize(serializer, options = {})
@serializer = serializer
@instance_options = options
end
# Subclasses that implement this method must first call
# options = serialization_options(options)
def serializable_hash(_options = nil)
fail NotImplementedError, 'This is an abstract method. Should be implemented at the concrete adapter.'
end
def as_json(options = nil)
serializable_hash(options)
end
def cache_key
self.class.cache_key
end
def fragment_cache(cached_hash, non_cached_hash)
self.class.fragment_cache(cached_hash, non_cached_hash)
end
private
# see https://github.com/rails-api/active_model_serializers/pull/965
# When <tt>options</tt> is +nil+, sets it to +{}+
def serialization_options(options)
options ||= {} # rubocop:disable Lint/UselessAssignment
end
def root
serializer.json_key.to_sym if serializer.json_key
end
end
end
end

View File

@ -1,21 +0,0 @@
module ActiveModelSerializers
module Adapter
class Json < Base
def serializable_hash(options = nil)
options = serialization_options(options)
serialized_hash = { root => Attributes.new(serializer, instance_options).serializable_hash(options) }
serialized_hash[meta_key] = meta unless meta.blank?
self.class.transform_key_casing!(serialized_hash, instance_options)
end
def meta
instance_options.fetch(:meta, nil)
end
def meta_key
instance_options.fetch(:meta_key, 'meta'.freeze)
end
end
end
end

View File

@ -1,530 +0,0 @@
# {http://jsonapi.org/format/ JSON API specification}
# rubocop:disable Style/AsciiComments
# TODO: implement!
# ☐ https://github.com/rails-api/active_model_serializers/issues/1235
# TODO: use uri_template in link generation?
# ☐ https://github.com/rails-api/active_model_serializers/pull/1282#discussion_r42528812
# see gem https://github.com/hannesg/uri_template
# spec http://tools.ietf.org/html/rfc6570
# impl https://developer.github.com/v3/#schema https://api.github.com/
# TODO: validate against a JSON schema document?
# ☐ https://github.com/rails-api/active_model_serializers/issues/1162
# ☑ https://github.com/rails-api/active_model_serializers/pull/1270
# TODO: Routing
# ☐ https://github.com/rails-api/active_model_serializers/pull/1476
# TODO: Query Params
# ☑ `include` https://github.com/rails-api/active_model_serializers/pull/1131
# ☑ `fields` https://github.com/rails-api/active_model_serializers/pull/700
# ☑ `page[number]=3&page[size]=1` https://github.com/rails-api/active_model_serializers/pull/1041
# ☐ `filter`
# ☐ `sort`
module ActiveModelSerializers
module Adapter
class JsonApi < Base
extend ActiveSupport::Autoload
autoload :Jsonapi
autoload :ResourceIdentifier
autoload :Relationship
autoload :Link
autoload :PaginationLinks
autoload :Meta
autoload :Error
autoload :Deserialization
def self.default_key_transform
:dash
end
def self.fragment_cache(cached_hash, non_cached_hash, root = true)
core_cached = cached_hash.first
core_non_cached = non_cached_hash.first
no_root_cache = cached_hash.delete_if { |key, _value| key == core_cached[0] }
no_root_non_cache = non_cached_hash.delete_if { |key, _value| key == core_non_cached[0] }
cached_resource = (core_cached[1]) ? core_cached[1].deep_merge(core_non_cached[1]) : core_non_cached[1]
hash = root ? { root => cached_resource } : cached_resource
hash.deep_merge no_root_non_cache.deep_merge no_root_cache
end
def initialize(serializer, options = {})
super
@include_directive = JSONAPI::IncludeDirective.new(options[:include], allow_wildcard: true)
@fieldset = options[:fieldset] || ActiveModel::Serializer::Fieldset.new(options.delete(:fields))
end
# {http://jsonapi.org/format/#crud Requests are transactional, i.e. success or failure}
# {http://jsonapi.org/format/#document-top-level data and errors MUST NOT coexist in the same document.}
def serializable_hash(*)
document = if serializer.success?
success_document
else
failure_document
end
self.class.transform_key_casing!(document, instance_options)
end
def fragment_cache(cached_hash, non_cached_hash)
root = !instance_options.include?(:include)
self.class.fragment_cache(cached_hash, non_cached_hash, root)
end
# {http://jsonapi.org/format/#document-top-level Primary data}
# definition:
# ☐ toplevel_data (required)
# ☐ toplevel_included
# ☑ toplevel_meta
# ☑ toplevel_links
# ☑ toplevel_jsonapi
# structure:
# {
# data: toplevel_data,
# included: toplevel_included,
# meta: toplevel_meta,
# links: toplevel_links,
# jsonapi: toplevel_jsonapi
# }.reject! {|_,v| v.nil? }
# rubocop:disable Metrics/CyclomaticComplexity
def success_document
is_collection = serializer.respond_to?(:each)
serializers = is_collection ? serializer : [serializer]
primary_data, included = resource_objects_for(serializers)
hash = {}
# toplevel_data
# definition:
# oneOf
# resource
# array of unique items of type 'resource'
# null
#
# description:
# The document's "primary data" is a representation of the resource or collection of resources
# targeted by a request.
#
# Singular: the resource object.
#
# Collection: one of an array of resource objects, an array of resource identifier objects, or
# an empty array ([]), for requests that target resource collections.
#
# None: null if the request is one that might correspond to a single resource, but doesn't currently.
# structure:
# if serializable_resource.resource?
# resource
# elsif serializable_resource.collection?
# [
# resource,
# resource
# ]
# else
# nil
# end
hash[:data] = is_collection ? primary_data : primary_data[0]
# toplevel_included
# alias included
# definition:
# array of unique items of type 'resource'
#
# description:
# To reduce the number of HTTP requests, servers **MAY** allow
# responses that include related resources along with the requested primary
# resources. Such responses are called "compound documents".
# structure:
# [
# resource,
# resource
# ]
hash[:included] = included if included.any?
Jsonapi.add!(hash)
if instance_options[:links]
hash[:links] ||= {}
hash[:links].update(instance_options[:links])
end
if is_collection && serializer.paginated?
hash[:links] ||= {}
hash[:links].update(pagination_links_for(serializer))
end
hash[:meta] = instance_options[:meta] unless instance_options[:meta].blank?
hash
end
# rubocop:enable Metrics/CyclomaticComplexity
# {http://jsonapi.org/format/#errors JSON API Errors}
# TODO: look into caching
# definition:
# ☑ toplevel_errors array (required)
# ☐ toplevel_meta
# ☐ toplevel_jsonapi
# structure:
# {
# errors: toplevel_errors,
# meta: toplevel_meta,
# jsonapi: toplevel_jsonapi
# }.reject! {|_,v| v.nil? }
# prs:
# https://github.com/rails-api/active_model_serializers/pull/1004
def failure_document
hash = {}
# PR Please :)
# Jsonapi.add!(hash)
# toplevel_errors
# definition:
# array of unique items of type 'error'
# structure:
# [
# error,
# error
# ]
if serializer.respond_to?(:each)
hash[:errors] = serializer.flat_map do |error_serializer|
Error.resource_errors(error_serializer, instance_options)
end
else
hash[:errors] = Error.resource_errors(serializer, instance_options)
end
hash
end
protected
attr_reader :fieldset
private
# {http://jsonapi.org/format/#document-resource-objects Primary data}
# resource
# definition:
# JSON Object
#
# properties:
# type (required) : String
# id (required) : String
# attributes
# relationships
# links
# meta
#
# description:
# "Resource objects" appear in a JSON API document to represent resources
# structure:
# {
# type: 'admin--some-user',
# id: '1336',
# attributes: attributes,
# relationships: relationships,
# links: links,
# meta: meta,
# }.reject! {|_,v| v.nil? }
# prs:
# type
# https://github.com/rails-api/active_model_serializers/pull/1122
# [x] https://github.com/rails-api/active_model_serializers/pull/1213
# https://github.com/rails-api/active_model_serializers/pull/1216
# https://github.com/rails-api/active_model_serializers/pull/1029
# links
# [x] https://github.com/rails-api/active_model_serializers/pull/1246
# [x] url helpers https://github.com/rails-api/active_model_serializers/issues/1269
# meta
# [x] https://github.com/rails-api/active_model_serializers/pull/1340
def resource_objects_for(serializers)
@primary = []
@included = []
@resource_identifiers = Set.new
serializers.each { |serializer| process_resource(serializer, true, @include_directive) }
serializers.each { |serializer| process_relationships(serializer, @include_directive) }
[@primary, @included]
end
def process_resource(serializer, primary, include_slice = {})
resource_identifier = ResourceIdentifier.new(serializer, instance_options).as_json
return false unless @resource_identifiers.add?(resource_identifier)
resource_object = resource_object_for(serializer, include_slice)
if primary
@primary << resource_object
else
@included << resource_object
end
true
end
def process_relationships(serializer, include_slice)
serializer.associations(include_slice).each do |association|
# TODO(BF): Process relationship without evaluating lazy_association
process_relationship(association.lazy_association.serializer, include_slice[association.key])
end
end
def process_relationship(serializer, include_slice)
if serializer.respond_to?(:each)
serializer.each { |s| process_relationship(s, include_slice) }
return
end
return unless serializer && serializer.object
return unless process_resource(serializer, false, include_slice)
process_relationships(serializer, include_slice)
end
# {http://jsonapi.org/format/#document-resource-object-attributes Document Resource Object Attributes}
# attributes
# definition:
# JSON Object
#
# patternProperties:
# ^(?!relationships$|links$)\\w[-\\w_]*$
#
# description:
# Members of the attributes object ("attributes") represent information about the resource
# object in which it's defined.
# Attributes may contain any valid JSON value
# structure:
# {
# foo: 'bar'
# }
def attributes_for(serializer, fields)
serializer.attributes(fields).except(:id)
end
# {http://jsonapi.org/format/#document-resource-objects Document Resource Objects}
def resource_object_for(serializer, include_slice = {})
resource_object = data_for(serializer, include_slice)
# toplevel_links
# definition:
# allOf
# ☐ links
# ☐ pagination
#
# description:
# Link members related to the primary data.
# structure:
# links.merge!(pagination)
# prs:
# https://github.com/rails-api/active_model_serializers/pull/1247
# https://github.com/rails-api/active_model_serializers/pull/1018
if (links = links_for(serializer)).any?
resource_object ||= {}
resource_object[:links] = links
end
# toplevel_meta
# alias meta
# definition:
# meta
# structure
# {
# :'git-ref' => 'abc123'
# }
if (meta = meta_for(serializer)).present?
resource_object ||= {}
resource_object[:meta] = meta
end
resource_object
end
def data_for(serializer, include_slice)
data = serializer.fetch(self) do
resource_object = ResourceIdentifier.new(serializer, instance_options).as_json
break nil if resource_object.nil?
requested_fields = fieldset && fieldset.fields_for(resource_object[:type])
attributes = attributes_for(serializer, requested_fields)
resource_object[:attributes] = attributes if attributes.any?
resource_object
end
data.tap do |resource_object|
next if resource_object.nil?
# NOTE(BF): the attributes are cached above, separately from the relationships, below.
requested_associations = fieldset.fields_for(resource_object[:type]) || '*'
relationships = relationships_for(serializer, requested_associations, include_slice)
resource_object[:relationships] = relationships if relationships.any?
end
end
# {http://jsonapi.org/format/#document-resource-object-relationships Document Resource Object Relationship}
# relationships
# definition:
# JSON Object
#
# patternProperties:
# ^\\w[-\\w_]*$"
#
# properties:
# data : relationshipsData
# links
# meta
#
# description:
#
# Members of the relationships object ("relationships") represent references from the
# resource object in which it's defined to other resource objects."
# structure:
# {
# links: links,
# meta: meta,
# data: relationshipsData
# }.reject! {|_,v| v.nil? }
#
# prs:
# links
# [x] https://github.com/rails-api/active_model_serializers/pull/1454
# meta
# [x] https://github.com/rails-api/active_model_serializers/pull/1454
# polymorphic
# [ ] https://github.com/rails-api/active_model_serializers/pull/1420
#
# relationshipsData
# definition:
# oneOf
# relationshipToOne
# relationshipToMany
#
# description:
# Member, whose value represents "resource linkage"
# structure:
# if has_one?
# relationshipToOne
# else
# relationshipToMany
# end
#
# definition:
# anyOf
# null
# linkage
#
# relationshipToOne
# description:
#
# References to other resource objects in a to-one ("relationship"). Relationships can be
# specified by including a member in a resource's links object.
#
# None: Describes an empty to-one relationship.
# structure:
# if has_related?
# linkage
# else
# nil
# end
#
# relationshipToMany
# definition:
# array of unique items of type 'linkage'
#
# description:
# An array of objects each containing "type" and "id" members for to-many relationships
# structure:
# [
# linkage,
# linkage
# ]
# prs:
# polymorphic
# [ ] https://github.com/rails-api/active_model_serializers/pull/1282
#
# linkage
# definition:
# type (required) : String
# id (required) : String
# meta
#
# description:
# The "type" and "id" to non-empty members.
# structure:
# {
# type: 'required-type',
# id: 'required-id',
# meta: meta
# }.reject! {|_,v| v.nil? }
def relationships_for(serializer, requested_associations, include_slice)
include_directive = JSONAPI::IncludeDirective.new(
requested_associations,
allow_wildcard: true
)
serializer.associations(include_directive, include_slice).each_with_object({}) do |association, hash|
hash[association.key] = Relationship.new(serializer, instance_options, association).as_json
end
end
# {http://jsonapi.org/format/#document-links Document Links}
# links
# definition:
# JSON Object
#
# properties:
# self : URI
# related : link
#
# description:
# A resource object **MAY** contain references to other resource objects ("relationships").
# Relationships may be to-one or to-many. Relationships can be specified by including a member
# in a resource's links object.
#
# A `self` members value is a URL for the relationship itself (a "relationship URL"). This
# URL allows the client to directly manipulate the relationship. For example, it would allow
# a client to remove an `author` from an `article` without deleting the people resource
# itself.
# structure:
# {
# self: 'http://example.com/etc',
# related: link
# }.reject! {|_,v| v.nil? }
def links_for(serializer)
serializer._links.each_with_object({}) do |(name, value), hash|
result = Link.new(serializer, value).as_json
hash[name] = result if result
end
end
# {http://jsonapi.org/format/#fetching-pagination Pagination Links}
# pagination
# definition:
# first : pageObject
# last : pageObject
# prev : pageObject
# next : pageObject
# structure:
# {
# first: pageObject,
# last: pageObject,
# prev: pageObject,
# next: pageObject
# }
#
# pageObject
# definition:
# oneOf
# URI
# null
#
# description:
# The <x> page of data
# structure:
# if has_page?
# 'http://example.com/some-page?page[number][x]'
# else
# nil
# end
# prs:
# https://github.com/rails-api/active_model_serializers/pull/1041
def pagination_links_for(serializer)
PaginationLinks.new(serializer.object, instance_options).as_json
end
# {http://jsonapi.org/format/#document-meta Docment Meta}
def meta_for(serializer)
Meta.new(serializer).as_json
end
end
end
end
# rubocop:enable Style/AsciiComments

View File

@ -1,213 +0,0 @@
module ActiveModelSerializers
module Adapter
class JsonApi
# NOTE(Experimental):
# This is an experimental feature. Both the interface and internals could be subject
# to changes.
module Deserialization
InvalidDocument = Class.new(ArgumentError)
module_function
# Transform a JSON API document, containing a single data object,
# into a hash that is ready for ActiveRecord::Base.new() and such.
# Raises InvalidDocument if the payload is not properly formatted.
#
# @param [Hash|ActionController::Parameters] document
# @param [Hash] options
# only: Array of symbols of whitelisted fields.
# except: Array of symbols of blacklisted fields.
# keys: Hash of translated keys (e.g. :author => :user).
# polymorphic: Array of symbols of polymorphic fields.
# @return [Hash]
#
# @example
# document = {
# data: {
# id: 1,
# type: 'post',
# attributes: {
# title: 'Title 1',
# date: '2015-12-20'
# },
# associations: {
# author: {
# data: {
# type: 'user',
# id: 2
# }
# },
# second_author: {
# data: nil
# },
# comments: {
# data: [{
# type: 'comment',
# id: 3
# },{
# type: 'comment',
# id: 4
# }]
# }
# }
# }
# }
#
# parse(document) #=>
# # {
# # title: 'Title 1',
# # date: '2015-12-20',
# # author_id: 2,
# # second_author_id: nil
# # comment_ids: [3, 4]
# # }
#
# parse(document, only: [:title, :date, :author],
# keys: { date: :published_at },
# polymorphic: [:author]) #=>
# # {
# # title: 'Title 1',
# # published_at: '2015-12-20',
# # author_id: '2',
# # author_type: 'people'
# # }
#
def parse!(document, options = {})
parse(document, options) do |invalid_payload, reason|
fail InvalidDocument, "Invalid payload (#{reason}): #{invalid_payload}"
end
end
# Same as parse!, but returns an empty hash instead of raising InvalidDocument
# on invalid payloads.
def parse(document, options = {})
document = document.dup.permit!.to_h if document.is_a?(ActionController::Parameters)
validate_payload(document) do |invalid_document, reason|
yield invalid_document, reason if block_given?
return {}
end
primary_data = document['data']
attributes = primary_data['attributes'] || {}
attributes['id'] = primary_data['id'] if primary_data['id']
relationships = primary_data['relationships'] || {}
filter_fields(attributes, options)
filter_fields(relationships, options)
hash = {}
hash.merge!(parse_attributes(attributes, options))
hash.merge!(parse_relationships(relationships, options))
hash
end
# Checks whether a payload is compliant with the JSON API spec.
#
# @api private
# rubocop:disable Metrics/CyclomaticComplexity
def validate_payload(payload)
unless payload.is_a?(Hash)
yield payload, 'Expected hash'
return
end
primary_data = payload['data']
unless primary_data.is_a?(Hash)
yield payload, { data: 'Expected hash' }
return
end
attributes = primary_data['attributes'] || {}
unless attributes.is_a?(Hash)
yield payload, { data: { attributes: 'Expected hash or nil' } }
return
end
relationships = primary_data['relationships'] || {}
unless relationships.is_a?(Hash)
yield payload, { data: { relationships: 'Expected hash or nil' } }
return
end
relationships.each do |(key, value)|
unless value.is_a?(Hash) && value.key?('data')
yield payload, { data: { relationships: { key => 'Expected hash with :data key' } } }
end
end
end
# rubocop:enable Metrics/CyclomaticComplexity
# @api private
def filter_fields(fields, options)
if (only = options[:only])
fields.slice!(*Array(only).map(&:to_s))
elsif (except = options[:except])
fields.except!(*Array(except).map(&:to_s))
end
end
# @api private
def field_key(field, options)
(options[:keys] || {}).fetch(field.to_sym, field).to_sym
end
# @api private
def parse_attributes(attributes, options)
transform_keys(attributes, options)
.map { |(k, v)| { field_key(k, options) => v } }
.reduce({}, :merge)
end
# Given an association name, and a relationship data attribute, build a hash
# mapping the corresponding ActiveRecord attribute to the corresponding value.
#
# @example
# parse_relationship(:comments, [{ 'id' => '1', 'type' => 'comments' },
# { 'id' => '2', 'type' => 'comments' }],
# {})
# # => { :comment_ids => ['1', '2'] }
# parse_relationship(:author, { 'id' => '1', 'type' => 'users' }, {})
# # => { :author_id => '1' }
# parse_relationship(:author, nil, {})
# # => { :author_id => nil }
# @param [Symbol] assoc_name
# @param [Hash] assoc_data
# @param [Hash] options
# @return [Hash{Symbol, Object}]
#
# @api private
def parse_relationship(assoc_name, assoc_data, options)
prefix_key = field_key(assoc_name, options).to_s.singularize
hash =
if assoc_data.is_a?(Array)
{ "#{prefix_key}_ids".to_sym => assoc_data.map { |ri| ri['id'] } }
else
{ "#{prefix_key}_id".to_sym => assoc_data ? assoc_data['id'] : nil }
end
polymorphic = (options[:polymorphic] || []).include?(assoc_name.to_sym)
if polymorphic
hash["#{prefix_key}_type".to_sym] = assoc_data.present? ? assoc_data['type'] : nil
end
hash
end
# @api private
def parse_relationships(relationships, options)
transform_keys(relationships, options)
.map { |(k, v)| parse_relationship(k, v['data'], options) }
.reduce({}, :merge)
end
# @api private
def transform_keys(hash, options)
transform = options[:key_transform] || :underscore
CaseTransform.send(transform, hash)
end
end
end
end
end

View File

@ -1,96 +0,0 @@
module ActiveModelSerializers
module Adapter
class JsonApi < Base
module Error
# rubocop:disable Style/AsciiComments
UnknownSourceTypeError = Class.new(ArgumentError)
# Builds a JSON API Errors Object
# {http://jsonapi.org/format/#errors JSON API Errors}
#
# @param [ActiveModel::Serializer::ErrorSerializer] error_serializer
# @return [Array<Symbol, Array<String>>] i.e. attribute_name, [attribute_errors]
def self.resource_errors(error_serializer, options)
error_serializer.as_json.flat_map do |attribute_name, attribute_errors|
attribute_name = JsonApi.send(:transform_key_casing!, attribute_name,
options)
attribute_error_objects(attribute_name, attribute_errors)
end
end
# definition:
# JSON Object
#
# properties:
# ☐ id : String
# ☐ status : String
# ☐ code : String
# ☐ title : String
# ☑ detail : String
# ☐ links
# ☐ meta
# ☑ error_source
#
# description:
# id : A unique identifier for this particular occurrence of the problem.
# status : The HTTP status code applicable to this problem, expressed as a string value
# code : An application-specific error code, expressed as a string value.
# title : A short, human-readable summary of the problem. It **SHOULD NOT** change from
# occurrence to occurrence of the problem, except for purposes of localization.
# detail : A human-readable explanation specific to this occurrence of the problem.
# structure:
# {
# title: 'SystemFailure',
# detail: 'something went terribly wrong',
# status: '500'
# }.merge!(errorSource)
def self.attribute_error_objects(attribute_name, attribute_errors)
attribute_errors.map do |attribute_error|
{
source: error_source(:pointer, attribute_name),
detail: attribute_error
}
end
end
# errorSource
# description:
# oneOf
# ☑ pointer : String
# ☑ parameter : String
#
# description:
# pointer: A JSON Pointer RFC6901 to the associated entity in the request document e.g. "/data"
# for a primary data object, or "/data/attributes/title" for a specific attribute.
# https://tools.ietf.org/html/rfc6901
#
# parameter: A string indicating which query parameter caused the error
# structure:
# if is_attribute?
# {
# pointer: '/data/attributes/red-button'
# }
# else
# {
# parameter: 'pres'
# }
# end
def self.error_source(source_type, attribute_name)
case source_type
when :pointer
{
pointer: ActiveModelSerializers::JsonPointer.new(:attribute, attribute_name)
}
when :parameter
{
parameter: attribute_name
}
else
fail UnknownSourceTypeError, "Unknown source type '#{source_type}' for attribute_name '#{attribute_name}'"
end
end
# rubocop:enable Style/AsciiComments
end
end
end
end

View File

@ -1,49 +0,0 @@
module ActiveModelSerializers
module Adapter
class JsonApi < Base
# {http://jsonapi.org/format/#document-jsonapi-object Jsonapi Object}
# toplevel_jsonapi
# definition:
# JSON Object
#
# properties:
# version : String
# meta
#
# description:
# An object describing the server's implementation
# structure:
# {
# version: ActiveModelSerializers.config.jsonapi_version,
# meta: ActiveModelSerializers.config.jsonapi_toplevel_meta
# }.reject! { |_, v| v.blank? }
# prs:
# https://github.com/rails-api/active_model_serializers/pull/1050
module Jsonapi
module_function
def add!(hash)
hash.merge!(object) if include_object?
end
def include_object?
ActiveModelSerializers.config.jsonapi_include_toplevel_object
end
# TODO: see if we can cache this
def object
object = {
jsonapi: {
version: ActiveModelSerializers.config.jsonapi_version,
meta: ActiveModelSerializers.config.jsonapi_toplevel_meta
}
}
object[:jsonapi].reject! { |_, v| v.blank? }
object
end
end
end
end
end

View File

@ -1,83 +0,0 @@
module ActiveModelSerializers
module Adapter
class JsonApi
# link
# definition:
# oneOf
# linkString
# linkObject
#
# description:
# A link **MUST** be represented as either: a string containing the link's URL or a link
# object."
# structure:
# if href?
# linkString
# else
# linkObject
# end
#
# linkString
# definition:
# URI
#
# description:
# A string containing the link's URL.
# structure:
# 'http://example.com/link-string'
#
# linkObject
# definition:
# JSON Object
#
# properties:
# href (required) : URI
# meta
# structure:
# {
# href: 'http://example.com/link-object',
# meta: meta,
# }.reject! {|_,v| v.nil? }
class Link
include SerializationContext::UrlHelpers
def initialize(serializer, value)
@_routes ||= nil # handles warning
# actionpack-4.0.13/lib/action_dispatch/routing/route_set.rb:417: warning: instance variable @_routes not initialized
@object = serializer.object
@scope = serializer.scope
# Use the return value of the block unless it is nil.
if value.respond_to?(:call)
@value = instance_eval(&value)
else
@value = value
end
end
def href(value)
@href = value
nil
end
def meta(value)
@meta = value
nil
end
def as_json
return @value if @value
hash = {}
hash[:href] = @href if defined?(@href)
hash[:meta] = @meta if defined?(@meta)
hash.any? ? hash : nil
end
protected
attr_reader :object, :scope
end
end
end
end

View File

@ -1,37 +0,0 @@
module ActiveModelSerializers
module Adapter
class JsonApi
# meta
# definition:
# JSON Object
#
# description:
# Non-standard meta-information that can not be represented as an attribute or relationship.
# structure:
# {
# attitude: 'adjustable'
# }
class Meta
def initialize(serializer)
@object = serializer.object
@scope = serializer.scope
# Use the return value of the block unless it is nil.
if serializer._meta.respond_to?(:call)
@value = instance_eval(&serializer._meta)
else
@value = serializer._meta
end
end
def as_json
@value
end
protected
attr_reader :object, :scope
end
end
end
end

View File

@ -1,69 +0,0 @@
module ActiveModelSerializers
module Adapter
class JsonApi < Base
class PaginationLinks
MissingSerializationContextError = Class.new(KeyError)
FIRST_PAGE = 1
attr_reader :collection, :context
def initialize(collection, adapter_options)
@collection = collection
@adapter_options = adapter_options
@context = adapter_options.fetch(:serialization_context) do
fail MissingSerializationContextError, <<-EOF.freeze
JsonApi::PaginationLinks requires a ActiveModelSerializers::SerializationContext.
Please pass a ':serialization_context' option or
override CollectionSerializer#paginated? to return 'false'.
EOF
end
end
def as_json
per_page = collection.try(:per_page) || collection.try(:limit_value) || collection.size
pages_from.each_with_object({}) do |(key, value), hash|
params = query_parameters.merge(page: { number: value, size: per_page }).to_query
hash[key] = "#{url(adapter_options)}?#{params}"
end
end
protected
attr_reader :adapter_options
private
def pages_from
return {} if collection.total_pages <= FIRST_PAGE
{}.tap do |pages|
pages[:self] = collection.current_page
unless collection.current_page == FIRST_PAGE
pages[:first] = FIRST_PAGE
pages[:prev] = collection.current_page - FIRST_PAGE
end
unless collection.current_page == collection.total_pages
pages[:next] = collection.current_page + FIRST_PAGE
pages[:last] = collection.total_pages
end
end
end
def url(options)
@url ||= options.fetch(:links, {}).fetch(:self, nil) || request_url
end
def request_url
@request_url ||= context.request_url
end
def query_parameters
@query_parameters ||= context.query_parameters
end
end
end
end
end

View File

@ -1,92 +0,0 @@
module ActiveModelSerializers
module Adapter
class JsonApi
class Relationship
# {http://jsonapi.org/format/#document-resource-object-related-resource-links Document Resource Object Related Resource Links}
# {http://jsonapi.org/format/#document-links Document Links}
# {http://jsonapi.org/format/#document-resource-object-linkage Document Resource Relationship Linkage}
# {http://jsonapi.org/format/#document-meta Document Meta}
def initialize(parent_serializer, serializable_resource_options, association)
@parent_serializer = parent_serializer
@association = association
@serializable_resource_options = serializable_resource_options
end
def as_json
hash = {}
hash[:data] = data_for(association) if association.include_data?
links = links_for(association)
hash[:links] = links if links.any?
meta = meta_for(association)
hash[:meta] = meta if meta
hash[:meta] = {} if hash.empty?
hash
end
protected
attr_reader :parent_serializer, :serializable_resource_options, :association
private
# TODO(BF): Avoid db hit on belong_to_ releationship by using foreign_key on self
def data_for(association)
if association.collection?
data_for_many(association)
else
data_for_one(association)
end
end
def data_for_one(association)
if association.belongs_to? &&
parent_serializer.object.respond_to?(association.reflection.foreign_key)
id = parent_serializer.object.send(association.reflection.foreign_key)
type = association.reflection.type.to_s
ResourceIdentifier.for_type_with_id(type, id, serializable_resource_options)
else
# TODO(BF): Process relationship without evaluating lazy_association
serializer = association.lazy_association.serializer
if (virtual_value = association.virtual_value)
virtual_value
elsif serializer && association.object
ResourceIdentifier.new(serializer, serializable_resource_options).as_json
else
nil
end
end
end
def data_for_many(association)
# TODO(BF): Process relationship without evaluating lazy_association
collection_serializer = association.lazy_association.serializer
if collection_serializer.respond_to?(:each)
collection_serializer.map do |serializer|
ResourceIdentifier.new(serializer, serializable_resource_options).as_json
end
elsif (virtual_value = association.virtual_value)
virtual_value
else
[]
end
end
def links_for(association)
association.links.each_with_object({}) do |(key, value), hash|
result = Link.new(parent_serializer, value).as_json
hash[key] = result if result
end
end
def meta_for(association)
meta = association.meta
meta.respond_to?(:call) ? parent_serializer.instance_eval(&meta) : meta
end
end
end
end
end

View File

@ -1,60 +0,0 @@
module ActiveModelSerializers
module Adapter
class JsonApi
class ResourceIdentifier
def self.type_for(class_name, serializer_type = nil, transform_options = {})
if serializer_type
raw_type = serializer_type
else
inflection =
if ActiveModelSerializers.config.jsonapi_resource_type == :singular
:singularize
else
:pluralize
end
raw_type = class_name.underscore
raw_type = ActiveSupport::Inflector.public_send(inflection, raw_type)
raw_type
.gsub!('/'.freeze, ActiveModelSerializers.config.jsonapi_namespace_separator)
raw_type
end
JsonApi.send(:transform_key_casing!, raw_type, transform_options)
end
def self.for_type_with_id(type, id, options)
return nil if id.blank?
{
id: id.to_s,
type: type_for(:no_class_needed, type, options)
}
end
# {http://jsonapi.org/format/#document-resource-identifier-objects Resource Identifier Objects}
def initialize(serializer, options)
@id = id_for(serializer)
@type = type_for(serializer, options)
end
def as_json
return nil if id.blank?
{ id: id, type: type }
end
protected
attr_reader :id, :type
private
def type_for(serializer, transform_options)
self.class.type_for(serializer.object.class.name, serializer._type, transform_options)
end
def id_for(serializer)
serializer.read_attribute_for_serialization(:id).to_s
end
end
end
end
end

View File

@ -1,9 +0,0 @@
module ActiveModelSerializers
module Adapter
class Null < Base
def serializable_hash(*)
{}
end
end
end
end

View File

@ -1,55 +0,0 @@
# Adapted from
# https://github.com/rails/rails/blob/7f18ea14c8/activejob/lib/active_job/callbacks.rb
require 'active_support/callbacks'
module ActiveModelSerializers
# = ActiveModelSerializers Callbacks
#
# ActiveModelSerializers provides hooks during the life cycle of serialization and
# allow you to trigger logic. Available callbacks are:
#
# * <tt>around_render</tt>
#
module Callbacks
extend ActiveSupport::Concern
include ActiveSupport::Callbacks
included do
define_callbacks :render
end
# These methods will be included into any ActiveModelSerializers object, adding
# callbacks for +render+.
module ClassMethods
# Defines a callback that will get called around the render method,
# whether it is as_json, to_json, or serializable_hash
#
# class ActiveModelSerializers::SerializableResource
# include ActiveModelSerializers::Callbacks
#
# around_render do |args, block|
# tag_logger do
# notify_render do
# block.call(args)
# end
# end
# end
#
# def as_json
# run_callbacks :render do
# adapter.as_json
# end
# end
# # Note: So that we can re-use the instrumenter for as_json, to_json, and
# # serializable_hash, we aren't using the usual format, which would be:
# # def render(args)
# # adapter.as_json
# # end
# end
#
def around_render(*filters, &blk)
set_callback(:render, :around, *filters, &blk)
end
end
end
end

View File

@ -1,54 +0,0 @@
##
# Provides a single method +deprecate+ to be used to declare when
# something is going away.
#
# class Legacy
# def self.klass_method
# # ...
# end
#
# def instance_method
# # ...
# end
#
# extend ActiveModelSerializers::Deprecate
# deprecate :instance_method, "ActiveModelSerializers::NewPlace#new_method"
#
# class << self
# extend ActiveModelSerializers::Deprecate
# deprecate :klass_method, :none
# end
# end
#
# Adapted from https://github.com/rubygems/rubygems/blob/1591331/lib/rubygems/deprecate.rb
module ActiveModelSerializers
module Deprecate
##
# Simple deprecation method that deprecates +name+ by wrapping it up
# in a dummy method. It warns on each call to the dummy method
# telling the user of +replacement+ (unless +replacement+ is :none) that it is planned to go away.
def deprecate(name, replacement)
old = "_deprecated_#{name}"
alias_method old, name
class_eval do
define_method(name) do |*args, &block|
target = is_a?(Module) ? "#{self}." : "#{self.class}#"
msg = ["NOTE: #{target}#{name} is deprecated",
replacement == :none ? ' with no replacement' : "; use #{replacement} instead",
"\n#{target}#{name} called from #{ActiveModelSerializers.location_of_caller.join(':')}"]
warn "#{msg.join}."
send old, *args, &block
end
end
end
def delegate_and_deprecate(method, delegee)
delegate method, to: delegee
deprecate method, "#{delegee.name}."
end
module_function :deprecate
module_function :delegate_and_deprecate
end
end

View File

@ -1,15 +0,0 @@
module ActiveModelSerializers
module Deserialization
module_function
def jsonapi_parse(*args)
Adapter::JsonApi::Deserialization.parse(*args)
end
# :nocov:
def jsonapi_parse!(*args)
Adapter::JsonApi::Deserialization.parse!(*args)
end
# :nocov:
end
end

View File

@ -1,14 +0,0 @@
module ActiveModelSerializers
module JsonPointer
module_function
POINTERS = {
attribute: '/data/attributes/%s'.freeze,
primary_data: '/data%s'.freeze
}.freeze
def new(pointer_type, value = nil)
format(POINTERS[pointer_type], value)
end
end
end

View File

@ -1,122 +0,0 @@
##
# ActiveModelSerializers::Logging
#
# https://github.com/rails/rails/blob/280654ef88/activejob/lib/active_job/logging.rb
#
module ActiveModelSerializers
module Logging
RENDER_EVENT = 'render.active_model_serializers'.freeze
extend ActiveSupport::Concern
included do
include ActiveModelSerializers::Callbacks
extend Macros
instrument_rendering
end
module ClassMethods
def instrument_rendering
around_render do |args, block|
tag_logger do
notify_render do
block.call(args)
end
end
end
end
end
# Macros that can be used to customize the logging of class or instance methods,
# by extending the class or its singleton.
#
# Adapted from:
# https://github.com/rubygems/rubygems/blob/cb28f5e991/lib/rubygems/deprecate.rb
#
# Provides a single method +notify+ to be used to declare when
# something a method notifies, with the argument +callback_name+ of the notification callback.
#
# class Adapter
# def self.klass_method
# # ...
# end
#
# def instance_method
# # ...
# end
#
# include ActiveModelSerializers::Logging::Macros
# notify :instance_method, :render
#
# class << self
# extend ActiveModelSerializers::Logging::Macros
# notify :klass_method, :render
# end
# end
module Macros
##
# Simple notify method that wraps up +name+
# in a dummy method. It notifies on with the +callback_name+ notifier on
# each call to the dummy method, telling what the current serializer and adapter
# are being rendered.
# Adapted from:
# https://github.com/rubygems/rubygems/blob/cb28f5e991/lib/rubygems/deprecate.rb
def notify(name, callback_name)
class_eval do
old = "_notifying_#{callback_name}_#{name}"
alias_method old, name
define_method name do |*args, &block|
run_callbacks callback_name do
send old, *args, &block
end
end
end
end
end
def notify_render(*)
event_name = RENDER_EVENT
ActiveSupport::Notifications.instrument(event_name, notify_render_payload) do
yield
end
end
def notify_render_payload
{
serializer: serializer || ActiveModel::Serializer::Null,
adapter: adapter || ActiveModelSerializers::Adapter::Null
}
end
private
def tag_logger(*tags)
if ActiveModelSerializers.logger.respond_to?(:tagged)
tags.unshift 'active_model_serializers'.freeze unless logger_tagged_by_active_model_serializers?
ActiveModelSerializers.logger.tagged(*tags) { yield }
else
yield
end
end
def logger_tagged_by_active_model_serializers?
ActiveModelSerializers.logger.formatter.current_tags.include?('active_model_serializers'.freeze)
end
class LogSubscriber < ActiveSupport::LogSubscriber
def render(event)
info do
serializer = event.payload[:serializer]
adapter = event.payload[:adapter]
duration = event.duration.round(2)
"Rendered #{serializer.name} with #{adapter.class} (#{duration}ms)"
end
end
def logger
ActiveModelSerializers.logger
end
end
end
end
ActiveModelSerializers::Logging::LogSubscriber.attach_to :active_model_serializers

View File

@ -1,80 +0,0 @@
module ActiveModelSerializers
module LookupChain
# Standard appending of Serializer to the resource name.
#
# Example:
# Author => AuthorSerializer
BY_RESOURCE = lambda do |resource_class, _serializer_class, _namespace|
serializer_from(resource_class)
end
# Uses the namespace of the resource to find the serializer
#
# Example:
# British::Author => British::AuthorSerializer
BY_RESOURCE_NAMESPACE = lambda do |resource_class, _serializer_class, _namespace|
resource_namespace = namespace_for(resource_class)
serializer_name = serializer_from(resource_class)
"#{resource_namespace}::#{serializer_name}"
end
# Uses the controller namespace of the resource to find the serializer
#
# Example:
# Api::V3::AuthorsController => Api::V3::AuthorSerializer
BY_NAMESPACE = lambda do |resource_class, _serializer_class, namespace|
resource_name = resource_class_name(resource_class)
namespace ? "#{namespace}::#{resource_name}Serializer" : nil
end
# Allows for serializers to be defined in parent serializers
# - useful if a relationship only needs a different set of attributes
# than if it were rendered independently.
#
# Example:
# class BlogSerializer < ActiveModel::Serializer
# class AuthorSerialier < ActiveModel::Serializer
# ...
# end
#
# belongs_to :author
# ...
# end
#
# The belongs_to relationship would be rendered with
# BlogSerializer::AuthorSerialier
BY_PARENT_SERIALIZER = lambda do |resource_class, serializer_class, _namespace|
return if serializer_class == ActiveModel::Serializer
serializer_name = serializer_from(resource_class)
"#{serializer_class}::#{serializer_name}"
end
DEFAULT = [
BY_PARENT_SERIALIZER,
BY_NAMESPACE,
BY_RESOURCE_NAMESPACE,
BY_RESOURCE
].freeze
module_function
def namespace_for(klass)
klass.name.deconstantize
end
def resource_class_name(klass)
klass.name.demodulize
end
def serializer_from_resource_name(name)
"#{name}Serializer"
end
def serializer_from(klass)
name = resource_class_name(klass)
serializer_from_resource_name(name)
end
end
end

View File

@ -1,130 +0,0 @@
# ActiveModelSerializers::Model is a convenient superclass for making your models
# from Plain-Old Ruby Objects (PORO). It also serves as a reference implementation
# that satisfies ActiveModel::Serializer::Lint::Tests.
require 'active_support/core_ext/hash'
module ActiveModelSerializers
class Model
include ActiveModel::Serializers::JSON
include ActiveModel::Model
# Declare names of attributes to be included in +attributes+ hash.
# Is only available as a class-method since the ActiveModel::Serialization mixin in Rails
# uses an +attribute_names+ local variable, which may conflict if we were to add instance methods here.
#
# @overload attribute_names
# @return [Array<Symbol>]
class_attribute :attribute_names, instance_writer: false, instance_reader: false
# Initialize +attribute_names+ for all subclasses. The array is usually
# mutated in the +attributes+ method, but can be set directly, as well.
self.attribute_names = []
# Easily declare instance attributes with setters and getters for each.
#
# To initialize an instance, all attributes must have setters.
# However, the hash returned by +attributes+ instance method will ALWAYS
# be the value of the initial attributes, regardless of what accessors are defined.
# The only way to change the change the attributes after initialization is
# to mutate the +attributes+ directly.
# Accessor methods do NOT mutate the attributes. (This is a bug).
#
# @note For now, the Model only supports the notion of 'attributes'.
# In the tests, there is a special Model that also supports 'associations'. This is
# important so that we can add accessors for values that should not appear in the
# attributes hash when modeling associations. It is not yet clear if it
# makes sense for a PORO to have associations outside of the tests.
#
# @overload attributes(names)
# @param names [Array<String, Symbol>]
# @param name [String, Symbol]
def self.attributes(*names)
self.attribute_names |= names.map(&:to_sym)
# Silence redefinition of methods warnings
ActiveModelSerializers.silence_warnings do
attr_accessor(*names)
end
end
# Opt-in to breaking change
def self.derive_attributes_from_names_and_fix_accessors
unless included_modules.include?(DeriveAttributesFromNamesAndFixAccessors)
prepend(DeriveAttributesFromNamesAndFixAccessors)
end
end
module DeriveAttributesFromNamesAndFixAccessors
def self.included(base)
# NOTE that +id+ will always be in +attributes+.
base.attributes :id
end
# Override the +attributes+ method so that the hash is derived from +attribute_names+.
#
# The fields in +attribute_names+ determines the returned hash.
# +attributes+ are returned frozen to prevent any expectations that mutation affects
# the actual values in the model.
def attributes
self.class.attribute_names.each_with_object({}) do |attribute_name, result|
result[attribute_name] = public_send(attribute_name).freeze
end.with_indifferent_access.freeze
end
end
# Support for validation and other ActiveModel::Errors
# @return [ActiveModel::Errors]
attr_reader :errors
# (see #updated_at)
attr_writer :updated_at
# The only way to change the attributes of an instance is to directly mutate the attributes.
# @example
#
# model.attributes[:foo] = :bar
# @return [Hash]
attr_reader :attributes
# @param attributes [Hash]
def initialize(attributes = {})
attributes ||= {} # protect against nil
@attributes = attributes.symbolize_keys.with_indifferent_access
@errors = ActiveModel::Errors.new(self)
super
end
# Defaults to the downcased model name.
# This probably isn't a good default, since it's not a unique instance identifier,
# but that's what is currently implemented \_('-')_/.
#
# @note Though +id+ is defined, it will only show up
# in +attributes+ when it is passed in to the initializer or added to +attributes+,
# such as <tt>attributes[:id] = 5</tt>.
# @return [String, Numeric, Symbol]
def id
attributes.fetch(:id) do
defined?(@id) ? @id : self.class.model_name.name && self.class.model_name.name.downcase
end
end
# When not set, defaults to the time the file was modified.
#
# @note Though +updated_at+ and +updated_at=+ are defined, it will only show up
# in +attributes+ when it is passed in to the initializer or added to +attributes+,
# such as <tt>attributes[:updated_at] = Time.current</tt>.
# @return [String, Numeric, Time]
def updated_at
attributes.fetch(:updated_at) do
defined?(@updated_at) ? @updated_at : File.mtime(__FILE__)
end
end
# To customize model behavior, this method must be redefined. However,
# there are other ways of setting the +cache_key+ a serializer uses.
# @return [String]
def cache_key
ActiveSupport::Cache.expand_cache_key([
self.class.model_name.name.downcase,
"#{id}-#{updated_at.strftime('%Y%m%d%H%M%S%9N')}"
].compact)
end
end
end

View File

@ -1,48 +0,0 @@
require 'rails/railtie'
require 'action_controller'
require 'action_controller/railtie'
require 'action_controller/serialization'
module ActiveModelSerializers
class Railtie < Rails::Railtie
config.to_prepare do
ActiveModel::Serializer.serializers_cache.clear
end
initializer 'active_model_serializers.action_controller' do
ActiveSupport.on_load(:action_controller) do
include(::ActionController::Serialization)
end
end
initializer 'active_model_serializers.prepare_serialization_context' do
SerializationContext.url_helpers = Rails.application.routes.url_helpers
SerializationContext.default_url_options = Rails.application.routes.default_url_options
end
# This hook is run after the action_controller railtie has set the configuration
# based on the *environment* configuration and before any config/initializers are run
# and also before eager_loading (if enabled).
initializer 'active_model_serializers.set_configs', after: 'action_controller.set_configs' do
ActiveModelSerializers.logger = Rails.configuration.action_controller.logger
ActiveModelSerializers.config.perform_caching = Rails.configuration.action_controller.perform_caching
# We want this hook to run after the config has been set, even if ActionController has already loaded.
ActiveSupport.on_load(:action_controller) do
ActiveModelSerializers.config.cache_store = ActionController::Base.cache_store
end
end
# :nocov:
generators do |app|
Rails::Generators.configure!(app.config.generators)
Rails::Generators.hidden_namespaces.uniq!
require 'generators/rails/resource_override'
end
# :nocov:
if Rails.env.test?
ActionController::TestCase.send(:include, ActiveModelSerializers::Test::Schema)
ActionController::TestCase.send(:include, ActiveModelSerializers::Test::Serializer)
end
end
end

View File

@ -1,78 +0,0 @@
# Based on discussion in https://github.com/rails/rails/pull/23712#issuecomment-184977238,
# the JSON API media type will have its own format/renderer.
#
# > We recommend the media type be registered on its own as jsonapi
# when a jsonapi Renderer and deserializer (Http::Parameters::DEFAULT_PARSERS) are added.
#
# Usage:
#
# ActiveSupport.on_load(:action_controller) do
# require 'active_model_serializers/register_jsonapi_renderer'
# end
#
# And then in controllers, use `render jsonapi: model` rather than `render json: model, adapter: :json_api`.
#
# For example, in a controller action, we can:
# respond_to do |format|
# format.jsonapi { render jsonapi: model }
# end
#
# or
#
# render jsonapi: model
#
# No wrapper format needed as it does not apply (i.e. no `wrap_parameters format: [jsonapi]`)
module ActiveModelSerializers
module Jsonapi
MEDIA_TYPE = 'application/vnd.api+json'.freeze
HEADERS = {
response: { 'CONTENT_TYPE'.freeze => MEDIA_TYPE },
request: { 'ACCEPT'.freeze => MEDIA_TYPE }
}.freeze
def self.install
# actionpack/lib/action_dispatch/http/mime_types.rb
Mime::Type.register MEDIA_TYPE, :jsonapi
if Rails::VERSION::MAJOR >= 5
ActionDispatch::Request.parameter_parsers[:jsonapi] = parser
else
ActionDispatch::ParamsParser::DEFAULT_PARSERS[Mime[:jsonapi]] = parser
end
# ref https://github.com/rails/rails/pull/21496
ActionController::Renderers.add :jsonapi do |json, options|
json = serialize_jsonapi(json, options).to_json(options) unless json.is_a?(String)
self.content_type ||= Mime[:jsonapi]
self.response_body = json
end
end
# Proposal: should actually deserialize the JSON API params
# to the hash format expected by `ActiveModel::Serializers::JSON`
# actionpack/lib/action_dispatch/http/parameters.rb
def self.parser
lambda do |body|
data = JSON.parse(body)
data = { _json: data } unless data.is_a?(Hash)
data.with_indifferent_access
end
end
module ControllerSupport
def serialize_jsonapi(json, options)
options[:adapter] = :json_api
options.fetch(:serialization_context) do
options[:serialization_context] = ActiveModelSerializers::SerializationContext.new(request)
end
get_serializer(json, options)
end
end
end
end
ActiveModelSerializers::Jsonapi.install
ActiveSupport.on_load(:action_controller) do
include ActiveModelSerializers::Jsonapi::ControllerSupport
end

View File

@ -1,82 +0,0 @@
require 'set'
module ActiveModelSerializers
class SerializableResource
ADAPTER_OPTION_KEYS = Set.new([:include, :fields, :adapter, :meta, :meta_key, :links, :serialization_context, :key_transform])
include ActiveModelSerializers::Logging
delegate :serializable_hash, :as_json, :to_json, to: :adapter
notify :serializable_hash, :render
notify :as_json, :render
notify :to_json, :render
# Primary interface to composing a resource with a serializer and adapter.
# @return the serializable_resource, ready for #as_json/#to_json/#serializable_hash.
def initialize(resource, options = {})
@resource = resource
@adapter_opts, @serializer_opts =
options.partition { |k, _| ADAPTER_OPTION_KEYS.include? k }.map { |h| Hash[h] }
end
def serialization_scope=(scope)
serializer_opts[:scope] = scope
end
def serialization_scope
serializer_opts[:scope]
end
def serialization_scope_name=(scope_name)
serializer_opts[:scope_name] = scope_name
end
# NOTE: if no adapter is available, returns the resource itself. (i.e. adapter is a no-op)
def adapter
@adapter ||= find_adapter
end
alias adapter_instance adapter
def find_adapter
return resource unless serializer?
adapter = catch :no_serializer do
ActiveModelSerializers::Adapter.create(serializer_instance, adapter_opts)
end
adapter || resource
end
def serializer_instance
@serializer_instance ||= serializer.new(resource, serializer_opts)
end
# Get serializer either explicitly :serializer or implicitly from resource
# Remove :serializer key from serializer_opts
# Remove :each_serializer if present and set as :serializer key
def serializer
@serializer ||=
begin
@serializer = serializer_opts.delete(:serializer)
@serializer ||= ActiveModel::Serializer.serializer_for(resource, serializer_opts)
if serializer_opts.key?(:each_serializer)
serializer_opts[:serializer] = serializer_opts.delete(:each_serializer)
end
@serializer
end
end
alias serializer_class serializer
# True when no explicit adapter given, or explicit appear is truthy (non-nil)
# False when explicit adapter is falsy (nil or false)
def use_adapter?
!(adapter_opts.key?(:adapter) && !adapter_opts[:adapter])
end
def serializer?
use_adapter? && !serializer.nil?
end
protected
attr_reader :resource, :adapter_opts, :serializer_opts
end
end

View File

@ -1,39 +0,0 @@
require 'active_support/core_ext/array/extract_options'
module ActiveModelSerializers
class SerializationContext
class << self
attr_writer :url_helpers, :default_url_options
def url_helpers
@url_helpers ||= Module.new
end
def default_url_options
@default_url_options ||= {}
end
end
module UrlHelpers
def self.included(base)
base.send(:include, SerializationContext.url_helpers)
end
def default_url_options
SerializationContext.default_url_options
end
end
attr_reader :request_url, :query_parameters, :key_transform
def initialize(*args)
options = args.extract_options!
if args.size == 1
request = args.pop
options[:request_url] = request.original_url[/\A[^?]+/]
options[:query_parameters] = request.query_parameters
end
@request_url = options.delete(:request_url)
@query_parameters = options.delete(:query_parameters)
@url_helpers = options.delete(:url_helpers) || self.class.url_helpers
@default_url_options = options.delete(:default_url_options) || self.class.default_url_options
end
end
end

View File

@ -1,7 +0,0 @@
module ActiveModelSerializers
module Test
extend ActiveSupport::Autoload
autoload :Serializer
autoload :Schema
end
end

Some files were not shown because too many files have changed in this diff Show More