active_model_serializers 0.8.3 → 0.10.0.rc3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +5 -0
- data/.rubocop.yml +82 -0
- data/.rubocop_todo.yml +315 -0
- data/.simplecov +99 -0
- data/.travis.yml +26 -20
- data/CHANGELOG.md +14 -67
- data/CONTRIBUTING.md +31 -0
- data/Gemfile +45 -1
- data/{MIT-LICENSE.txt → LICENSE.txt} +3 -2
- data/README.md +186 -488
- data/Rakefile +33 -12
- data/active_model_serializers.gemspec +49 -23
- data/appveyor.yml +25 -0
- data/docs/README.md +29 -0
- data/docs/general/adapters.md +110 -0
- data/docs/general/configuration_options.md +11 -0
- data/docs/general/getting_started.md +73 -0
- data/docs/howto/add_pagination_links.md +112 -0
- data/docs/howto/add_root_key.md +51 -0
- data/docs/howto/outside_controller_use.md +42 -0
- data/lib/action_controller/serialization.rb +31 -31
- data/lib/active_model/serializable_resource.rb +70 -0
- data/lib/active_model/serializer/adapter/flatten_json.rb +12 -0
- data/lib/active_model/serializer/adapter/fragment_cache.rb +75 -0
- data/lib/active_model/serializer/adapter/json/fragment_cache.rb +5 -0
- data/lib/active_model/serializer/adapter/json.rb +47 -0
- data/lib/active_model/serializer/adapter/json_api/fragment_cache.rb +13 -0
- data/lib/active_model/serializer/adapter/json_api/pagination_links.rb +50 -0
- data/lib/active_model/serializer/adapter/json_api.rb +158 -0
- data/lib/active_model/serializer/adapter/null.rb +5 -0
- data/lib/active_model/serializer/adapter.rb +159 -0
- data/lib/active_model/serializer/array_serializer.rb +40 -0
- data/lib/active_model/serializer/association.rb +20 -0
- data/lib/active_model/serializer/associations.rb +83 -219
- data/lib/active_model/serializer/belongs_to_reflection.rb +10 -0
- data/lib/active_model/serializer/collection_reflection.rb +7 -0
- data/lib/active_model/serializer/configuration.rb +14 -0
- data/lib/active_model/serializer/fieldset.rb +40 -0
- data/lib/active_model/serializer/has_many_reflection.rb +10 -0
- data/lib/active_model/serializer/has_one_reflection.rb +10 -0
- data/lib/active_model/serializer/lint.rb +129 -0
- data/lib/active_model/serializer/railtie.rb +15 -0
- data/lib/active_model/serializer/reflection.rb +74 -0
- data/lib/active_model/serializer/singular_reflection.rb +7 -0
- data/lib/active_model/serializer/utils.rb +35 -0
- data/lib/active_model/{serializers → serializer}/version.rb +1 -1
- data/lib/active_model/serializer.rb +121 -465
- data/lib/active_model_serializers.rb +26 -88
- data/lib/generators/serializer/USAGE +0 -3
- data/lib/generators/serializer/resource_override.rb +12 -0
- data/lib/generators/serializer/serializer_generator.rb +8 -13
- data/lib/generators/serializer/templates/serializer.rb.erb +8 -0
- data/lib/tasks/rubocop.rake +0 -0
- data/test/action_controller/adapter_selector_test.rb +53 -0
- data/test/action_controller/explicit_serializer_test.rb +134 -0
- data/test/action_controller/json_api/linked_test.rb +179 -0
- data/test/action_controller/json_api/pagination_test.rb +116 -0
- data/test/{serialization_scope_name_test.rb → action_controller/serialization_scope_name_test.rb} +15 -15
- data/test/action_controller/serialization_test.rb +420 -0
- data/test/active_record_test.rb +9 -0
- data/test/adapter/fragment_cache_test.rb +37 -0
- data/test/adapter/json/belongs_to_test.rb +47 -0
- data/test/adapter/json/collection_test.rb +82 -0
- data/test/adapter/json/has_many_test.rb +47 -0
- data/test/adapter/json_api/belongs_to_test.rb +157 -0
- data/test/adapter/json_api/collection_test.rb +95 -0
- data/test/adapter/json_api/has_many_embed_ids_test.rb +45 -0
- data/test/adapter/json_api/has_many_explicit_serializer_test.rb +98 -0
- data/test/adapter/json_api/has_many_test.rb +145 -0
- data/test/adapter/json_api/has_one_test.rb +81 -0
- data/test/adapter/json_api/json_api_test.rb +37 -0
- data/test/adapter/json_api/linked_test.rb +283 -0
- data/test/adapter/json_api/pagination_links_test.rb +115 -0
- data/test/adapter/json_api/resource_type_config_test.rb +59 -0
- data/test/adapter/json_test.rb +47 -0
- data/test/adapter/null_test.rb +25 -0
- data/test/adapter_test.rb +42 -0
- data/test/array_serializer_test.rb +99 -73
- data/test/capture_warnings.rb +65 -0
- data/test/fixtures/active_record.rb +56 -0
- data/test/fixtures/poro.rb +261 -0
- data/test/generators/scaffold_controller_generator_test.rb +23 -0
- data/test/generators/serializer_generator_test.rb +56 -0
- data/test/lint_test.rb +37 -0
- data/test/logger_test.rb +18 -0
- data/test/poro_test.rb +9 -0
- data/test/serializable_resource_test.rb +27 -0
- data/test/serializers/adapter_for_test.rb +170 -0
- data/test/serializers/association_macros_test.rb +36 -0
- data/test/serializers/associations_test.rb +150 -0
- data/test/serializers/attribute_test.rb +62 -0
- data/test/serializers/attributes_test.rb +57 -0
- data/test/serializers/cache_test.rb +165 -0
- data/test/serializers/configuration_test.rb +15 -0
- data/test/serializers/fieldset_test.rb +25 -0
- data/test/serializers/meta_test.rb +121 -0
- data/test/serializers/options_test.rb +21 -0
- data/test/serializers/root_test.rb +21 -0
- data/test/serializers/serializer_for_test.rb +65 -0
- data/test/support/rails_app.rb +21 -0
- data/test/support/serialization_testing.rb +13 -0
- data/test/support/simplecov.rb +6 -0
- data/test/support/stream_capture.rb +50 -0
- data/test/support/test_case.rb +5 -0
- data/test/test_helper.rb +48 -24
- data/test/utils/include_args_to_hash_test.rb +79 -0
- metadata +219 -47
- data/DESIGN.textile +0 -586
- data/Gemfile.edge +0 -9
- data/bench/perf.rb +0 -43
- data/cruft.md +0 -19
- data/lib/active_model/array_serializer.rb +0 -104
- data/lib/active_record/serializer_override.rb +0 -16
- data/lib/generators/resource_override.rb +0 -13
- data/lib/generators/serializer/templates/serializer.rb +0 -19
- data/test/association_test.rb +0 -592
- data/test/caching_test.rb +0 -96
- data/test/generators_test.rb +0 -85
- data/test/no_serialization_scope_test.rb +0 -34
- data/test/serialization_test.rb +0 -392
- data/test/serializer_support_test.rb +0 -51
- data/test/serializer_test.rb +0 -1465
- data/test/test_fakes.rb +0 -217
data/Rakefile
CHANGED
@@ -1,18 +1,39 @@
|
|
1
|
-
|
2
|
-
require
|
3
|
-
|
1
|
+
begin
|
2
|
+
require 'simplecov'
|
3
|
+
rescue LoadError
|
4
|
+
end
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
require 'bundler/gem_tasks'
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'rubocop'
|
10
|
+
require 'rubocop/rake_task'
|
11
|
+
rescue LoadError
|
12
|
+
else
|
13
|
+
Rake::Task[:rubocop].clear if Rake::Task.task_defined?(:rubocop)
|
14
|
+
if !defined?(::Rubinius)
|
15
|
+
Rake::Task[:rubocop].clear if Rake::Task.task_defined?(:rubocop)
|
16
|
+
desc 'Execute rubocop'
|
17
|
+
RuboCop::RakeTask.new(:rubocop) do |task|
|
18
|
+
task.options = ['--rails', '--display-cop-names', '--display-style-guide']
|
19
|
+
task.fail_on_error = true
|
20
|
+
end
|
21
|
+
else
|
22
|
+
desc 'No-op rubocop to avoid rbx segfault'
|
23
|
+
task :rubocop do
|
24
|
+
puts 'Skipping rubocop on rbx due to segfault'
|
25
|
+
puts 'https://github.com/rubinius/rubinius/issues/3499'
|
26
|
+
end
|
27
|
+
end
|
11
28
|
end
|
12
29
|
|
13
|
-
|
14
|
-
|
15
|
-
|
30
|
+
require 'rake/testtask'
|
31
|
+
|
32
|
+
Rake::TestTask.new do |t|
|
33
|
+
t.libs << 'test'
|
34
|
+
t.test_files = FileList['test/**/*_test.rb']
|
35
|
+
t.ruby_opts = ['-r./test/test_helper.rb']
|
36
|
+
t.verbose = true
|
16
37
|
end
|
17
38
|
|
18
39
|
task :default => :test
|
@@ -1,24 +1,50 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
require
|
5
|
-
|
6
|
-
Gem::Specification.new do |
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'active_model/serializer/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'active_model_serializers'
|
8
|
+
spec.version = ActiveModel::Serializer::VERSION
|
9
|
+
spec.platform = Gem::Platform::RUBY
|
10
|
+
spec.authors = ['Steve Klabnik']
|
11
|
+
spec.email = ['steve@steveklabnik.com']
|
12
|
+
spec.summary = 'Conventions-based JSON generation for Rails.'
|
13
|
+
spec.description = 'ActiveModel::Serializers allows you to generate your JSON in an object-oriented and convention-driven manner.'
|
14
|
+
spec.homepage = 'https://github.com/rails-api/active_model_serializers'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0")
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.required_ruby_version = '>= 1.9.3'
|
22
|
+
|
23
|
+
rails_versions = '>= 4.0'
|
24
|
+
spec.add_runtime_dependency 'activemodel', rails_versions
|
25
|
+
# 'activesupport', rails_versions
|
26
|
+
# 'builder'
|
27
|
+
|
28
|
+
spec.add_runtime_dependency 'actionpack', rails_versions
|
29
|
+
# 'activesupport', rails_versions
|
30
|
+
# 'rack'
|
31
|
+
# 'rack-test', '~> 0.6.2'
|
32
|
+
|
33
|
+
spec.add_runtime_dependency 'railties', rails_versions
|
34
|
+
# 'activesupport', rails_versions
|
35
|
+
# 'actionpack', rails_versions
|
36
|
+
# 'rake', '>= 0.8.7'
|
37
|
+
|
38
|
+
# 'activesupport', rails_versions
|
39
|
+
# 'i18n,
|
40
|
+
# 'tzinfo'
|
41
|
+
# 'minitest'
|
42
|
+
# 'thread_safe'
|
43
|
+
|
44
|
+
# Soft dependency for pagination
|
45
|
+
spec.add_development_dependency 'kaminari', ' ~> 0.16.3'
|
46
|
+
spec.add_development_dependency 'will_paginate', '~> 3.0', '>= 3.0.7'
|
47
|
+
|
48
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
49
|
+
spec.add_development_dependency 'timecop', '~> 0.7'
|
24
50
|
end
|
data/appveyor.yml
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
version: '{build}'
|
2
|
+
|
3
|
+
skip_tags: true
|
4
|
+
|
5
|
+
environment:
|
6
|
+
matrix:
|
7
|
+
- ruby_version: "193"
|
8
|
+
- ruby_version: "193-x64"
|
9
|
+
- ruby_version: "200"
|
10
|
+
- ruby_version: "200-x64"
|
11
|
+
- ruby_version: "21"
|
12
|
+
- ruby_version: "21-x64"
|
13
|
+
|
14
|
+
install:
|
15
|
+
- SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
|
16
|
+
- ruby --version
|
17
|
+
- gem --version
|
18
|
+
- gem install bundler
|
19
|
+
- bundler --version
|
20
|
+
- bundle install --retry=3
|
21
|
+
|
22
|
+
test_script:
|
23
|
+
- bundle exec rake
|
24
|
+
|
25
|
+
build: off
|
data/docs/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Docs - ActiveModel::Serializer 0.10.x
|
2
|
+
|
3
|
+
This is the documentation of AMS, it's focused on the **0.10.x version.**
|
4
|
+
|
5
|
+
-----
|
6
|
+
|
7
|
+
## General
|
8
|
+
|
9
|
+
- [Getting Started](general/getting_started.md)
|
10
|
+
- [Adapters](general/adapters.md)
|
11
|
+
- [Configuration Options](general/configuration_options.md)
|
12
|
+
|
13
|
+
## How to
|
14
|
+
|
15
|
+
- [How to add root key](howto/add_root_key.md)
|
16
|
+
- [How to add pagination links](howto/add_pagination_links.md)
|
17
|
+
- [Using AMS Outside Of Controllers](howto/outside_controller_use.md)
|
18
|
+
|
19
|
+
## Getting Help
|
20
|
+
|
21
|
+
If you find a bug, please report an [Issue](https://github.com/rails-api/active_model_serializers/issues/new).
|
22
|
+
|
23
|
+
If you have a question, please [post to Stack Overflow](http://stackoverflow.com/questions/tagged/active-model-serializers).
|
24
|
+
|
25
|
+
Thanks!
|
26
|
+
|
27
|
+
## Contributing
|
28
|
+
|
29
|
+
See [CONTRIBUTING.md](https://github.com/rails-api/active_model_serializers/blob/master/CONTRIBUTING.md)
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# Adapters
|
2
|
+
|
3
|
+
AMS does this through two components: **serializers** and **adapters**.
|
4
|
+
Serializers describe _which_ attributes and relationships should be serialized.
|
5
|
+
Adapters describe _how_ attributes and relationships should be serialized.
|
6
|
+
You can use one of the built-in adapters (```FlattenJSON``` is the default one) or create one by yourself, but you won't need to implement an adapter unless you wish to use a new format or media type with AMS.
|
7
|
+
|
8
|
+
## Built in Adapters
|
9
|
+
|
10
|
+
### FlattenJSON - Default
|
11
|
+
|
12
|
+
It's the default adapter, it generates a json response without a root key.
|
13
|
+
Doesn't follow any specifc convention.
|
14
|
+
|
15
|
+
### JSON
|
16
|
+
|
17
|
+
It also generates a json response but always with a root key. The root key **can't be overridden**, and will be automatically defined accordingly to the objects being serialized.
|
18
|
+
Doesn't follow any specifc convention.
|
19
|
+
|
20
|
+
### JSONAPI
|
21
|
+
|
22
|
+
This adapter follows **version 1.0** of the format specified in
|
23
|
+
[jsonapi.org/format](http://jsonapi.org/format). It will include the associated
|
24
|
+
resources in the `"included"` member when the resource names are included in the
|
25
|
+
`include` option.
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
render @posts, include: ['authors', 'comments']
|
29
|
+
```
|
30
|
+
|
31
|
+
or
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
render @posts, include: 'authors,comments'
|
35
|
+
```
|
36
|
+
|
37
|
+
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, or a mix of both.
|
38
|
+
|
39
|
+
## Choosing an adapter
|
40
|
+
|
41
|
+
If you want to use a specify a default adapter, such as JsonApi, you can change this in an initializer:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
ActiveModel::Serializer.config.adapter = ActiveModel::Serializer::Adapter::JsonApi
|
45
|
+
```
|
46
|
+
|
47
|
+
or
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
ActiveModel::Serializer.config.adapter = :json_api
|
51
|
+
```
|
52
|
+
|
53
|
+
If you want to have a root key for each resource in your responses, you should use the Json or
|
54
|
+
JsonApi adapters instead of the default FlattenJson:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
ActiveModel::Serializer.config.adapter = :json
|
58
|
+
```
|
59
|
+
|
60
|
+
## Advanced adapter configuration
|
61
|
+
|
62
|
+
### Registering an adapter
|
63
|
+
|
64
|
+
The default adapter can be configured, as above, to use any class given to it.
|
65
|
+
|
66
|
+
An adapter may also be specified, e.g. when rendering, as a class or as a symbol.
|
67
|
+
If a symbol, then the adapter must be, e.g. `:great_example`,
|
68
|
+
`ActiveModel::Serializer::Adapter::GreatExample`, or registered.
|
69
|
+
|
70
|
+
There are two ways to register an adapter:
|
71
|
+
|
72
|
+
1) The simplest, is to subclass `ActiveModel::Serializer::Adapter`, e.g. the below will
|
73
|
+
register the `Example::UsefulAdapter` as `:useful_adapter`.
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
module Example
|
77
|
+
class UsefulAdapter < ActiveModel::Serializer::Adapter
|
78
|
+
end
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
You'll notice that the name it registers is the class name underscored, not the full namespace.
|
83
|
+
|
84
|
+
Under the covers, when the `ActiveModel::Serializer::Adapter` is subclassed, it registers
|
85
|
+
the subclass as `register(:useful_adapter, Example::UsefulAdapter)`
|
86
|
+
|
87
|
+
2) Any class can be registered as an adapter by calling `register` directly on the
|
88
|
+
`ActiveModel::Serializer::Adapter` class. e.g., the below registers `MyAdapter` as
|
89
|
+
`:special_adapter`.
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
class MyAdapter; end
|
93
|
+
ActiveModel::Serializer::Adapter.register(:special_adapter, MyAdapter)
|
94
|
+
```
|
95
|
+
|
96
|
+
### Looking up an adapter
|
97
|
+
|
98
|
+
| Method | Return value |
|
99
|
+
| :------------ |:---------------|
|
100
|
+
| `ActiveModel::Serializer::Adapter.adapter_map` | A Hash of all known adapters `{ adapter_name => adapter_class }` |
|
101
|
+
| `ActiveModel::Serializer::Adapter.adapters` | A (sorted) Array of all known `adapter_names` |
|
102
|
+
| `ActiveModel::Serializer::Adapter.lookup(name_or_klass)` | The `adapter_class`, else raises an `ActiveModel::Serializer::Adapter::UnknownAdapter` error |
|
103
|
+
| `ActiveModel::Serializer::Adapter.adapter_class(adapter)` | Delegates to `ActiveModel::Serializer::Adapter.lookup(adapter)` |
|
104
|
+
| `ActiveModel::Serializer.adapter` | A convenience method for `ActiveModel::Serializer::Adapter.lookup(config.adapter)` |
|
105
|
+
|
106
|
+
The registered adapter name is always a String, but may be looked up as a Symbol or String.
|
107
|
+
Helpfully, the Symbol or String is underscored, so that `get(:my_adapter)` and `get("MyAdapter")`
|
108
|
+
may both be used.
|
109
|
+
|
110
|
+
For more information, see [the Adapter class on GitHub](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model/serializer/adapter.rb)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# Configuration Options
|
2
|
+
|
3
|
+
The following configuration options can be set on `ActiveModel::Serializer.config` inside an initializer.
|
4
|
+
|
5
|
+
## General
|
6
|
+
|
7
|
+
- `adapter`: The [adapter](adapters.md) to use. Possible values: `:flatten_json, :json, :json_api`. Default: `:flatten_json`.
|
8
|
+
|
9
|
+
## JSON API
|
10
|
+
|
11
|
+
- `jsonapi_resource_type`: Whether the `type` attributes of resources should be singular or plural. Possible values: `:singular, :plural`. Default: `:plural`.
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# Getting Started
|
2
|
+
|
3
|
+
## Installation
|
4
|
+
|
5
|
+
### ActiveModel::Serializer is already included on Rails >= 5
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```
|
10
|
+
gem 'active_model_serializers'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
```
|
16
|
+
$ bundle
|
17
|
+
```
|
18
|
+
|
19
|
+
## Creating a Serializer
|
20
|
+
|
21
|
+
The easiest way to create a new serializer is to generate a new resource, which
|
22
|
+
will generate a serializer at the same time:
|
23
|
+
|
24
|
+
```
|
25
|
+
$ rails g resource post title:string body:string
|
26
|
+
```
|
27
|
+
|
28
|
+
This will generate a serializer in `app/serializers/post_serializer.rb` for
|
29
|
+
your new model. You can also generate a serializer for an existing model with
|
30
|
+
the serializer generator:
|
31
|
+
|
32
|
+
```
|
33
|
+
$ rails g serializer post
|
34
|
+
```
|
35
|
+
|
36
|
+
The generated seralizer will contain basic `attributes` and
|
37
|
+
`has_many`/`has_one`/`belongs_to` declarations, based on the model. For example:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
class PostSerializer < ActiveModel::Serializer
|
41
|
+
attributes :title, :body
|
42
|
+
|
43
|
+
has_many :comments
|
44
|
+
has_one :author
|
45
|
+
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
and
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
class CommentSerializer < ActiveModel::Serializer
|
53
|
+
attributes :name, :body
|
54
|
+
|
55
|
+
belongs_to :post_id
|
56
|
+
|
57
|
+
end
|
58
|
+
```
|
59
|
+
|
60
|
+
## Rails Integration
|
61
|
+
|
62
|
+
AMS will automatically integrate with you Rails app, you won't need to update your controller, this is a example of how it will look like:
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
class PostsController < ApplicationController
|
66
|
+
|
67
|
+
def show
|
68
|
+
@post = Post.find(params[:id])
|
69
|
+
render json: @post
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
```
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# How to add pagination links
|
2
|
+
|
3
|
+
### JSON-API adapter
|
4
|
+
|
5
|
+
Pagination links will be included in your response automatically as long as the resource is paginated and if you are using a ```JSON-API``` adapter.
|
6
|
+
|
7
|
+
If you want pagination links in your response, use [Kaminari](https://github.com/amatsuda/kaminari) or [WillPaginate](https://github.com/mislav/will_paginate).
|
8
|
+
|
9
|
+
###### Kaminari examples
|
10
|
+
```ruby
|
11
|
+
#array
|
12
|
+
@posts = Kaminari.paginate_array([1, 2, 3]).page(3).per(1)
|
13
|
+
render json: @posts
|
14
|
+
|
15
|
+
#active_record
|
16
|
+
@posts = Post.page(3).per(1)
|
17
|
+
render json: @posts
|
18
|
+
```
|
19
|
+
|
20
|
+
###### WillPaginate examples
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
#array
|
24
|
+
@posts = [1,2,3].paginate(page: 3, per_page: 1)
|
25
|
+
render json: @posts
|
26
|
+
|
27
|
+
#active_record
|
28
|
+
@posts = Post.page(3).per_page(1)
|
29
|
+
render json: @posts
|
30
|
+
```
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
ActiveModel::Serializer.config.adapter = :json_api
|
34
|
+
```
|
35
|
+
|
36
|
+
ex:
|
37
|
+
```json
|
38
|
+
{
|
39
|
+
"data": [
|
40
|
+
{
|
41
|
+
"type": "articles",
|
42
|
+
"id": "3",
|
43
|
+
"attributes": {
|
44
|
+
"title": "JSON API paints my bikeshed!",
|
45
|
+
"body": "The shortest article. Ever.",
|
46
|
+
"created": "2015-05-22T14:56:29.000Z",
|
47
|
+
"updated": "2015-05-22T14:56:28.000Z"
|
48
|
+
}
|
49
|
+
}
|
50
|
+
],
|
51
|
+
"links": {
|
52
|
+
"self": "http://example.com/articles?page[number]=3&page[size]=1",
|
53
|
+
"first": "http://example.com/articles?page[number]=1&page[size]=1",
|
54
|
+
"prev": "http://example.com/articles?page[number]=2&page[size]=1",
|
55
|
+
"next": "http://example.com/articles?page[number]=4&page[size]=1",
|
56
|
+
"last": "http://example.com/articles?page[number]=13&page[size]=1"
|
57
|
+
}
|
58
|
+
}
|
59
|
+
```
|
60
|
+
|
61
|
+
AMS 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).
|
62
|
+
|
63
|
+
|
64
|
+
### JSON adapter
|
65
|
+
|
66
|
+
If you are using `JSON` adapter, pagination links will not be included automatically, but it is possible to do so using `meta` key.
|
67
|
+
|
68
|
+
In your action specify a custom serializer.
|
69
|
+
```ruby
|
70
|
+
render json: @posts, serializer: PaginatedSerializer, each_serializer: PostPreviewSerializer
|
71
|
+
```
|
72
|
+
|
73
|
+
And then, you could do something like the following class.
|
74
|
+
```ruby
|
75
|
+
class PaginatedSerializer < ActiveModel::Serializer::ArraySerializer
|
76
|
+
def initialize(object, options={})
|
77
|
+
meta_key = options[:meta_key] || :meta
|
78
|
+
options[meta_key] ||= {}
|
79
|
+
options[meta_key] = {
|
80
|
+
current_page: object.current_page,
|
81
|
+
next_page: object.next_page,
|
82
|
+
prev_page: object.prev_page,
|
83
|
+
total_pages: object.total_pages,
|
84
|
+
total_count: object.total_count
|
85
|
+
}
|
86
|
+
super(object, options)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
```
|
90
|
+
ex.
|
91
|
+
```json
|
92
|
+
{
|
93
|
+
"articles": [
|
94
|
+
{
|
95
|
+
"id": 2,
|
96
|
+
"title": "JSON API paints my bikeshed!",
|
97
|
+
"body": "The shortest article. Ever."
|
98
|
+
}
|
99
|
+
],
|
100
|
+
"meta": {
|
101
|
+
"current_page": 3,
|
102
|
+
"next_page": 4,
|
103
|
+
"prev_page": 2,
|
104
|
+
"total_pages": 10,
|
105
|
+
"total_count": 10
|
106
|
+
}
|
107
|
+
}
|
108
|
+
```
|
109
|
+
|
110
|
+
### FlattenJSON adapter
|
111
|
+
|
112
|
+
This adapter does not allow us to use `meta` key, due to that it is not possible to add pagination links.
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# How to add root key
|
2
|
+
|
3
|
+
Add the root key to your API is quite simple with AMS. The **Adapter** is what determines the format of your JSON response. The default adapter is the ```FlattenJSON``` which doesn't have the root key, so your response is something similar to:
|
4
|
+
|
5
|
+
```json
|
6
|
+
{
|
7
|
+
"id": 1,
|
8
|
+
"title": "Awesome Post Tile",
|
9
|
+
"content": "Post content"
|
10
|
+
}
|
11
|
+
```
|
12
|
+
|
13
|
+
In order to add the root key you need to use the ```JSON``` Adapter, you can change this in an initializer:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
ActiveModel::Serializer.config.adapter = :json
|
17
|
+
```
|
18
|
+
|
19
|
+
You can also specify a class as adapter, as long as it complies with the AMS adapters interface.
|
20
|
+
It will add the root key to all your serialized endpoints.
|
21
|
+
|
22
|
+
ex:
|
23
|
+
|
24
|
+
```json
|
25
|
+
{
|
26
|
+
"post": {
|
27
|
+
"id": 1,
|
28
|
+
"title": "Awesome Post Tile",
|
29
|
+
"content": "Post content"
|
30
|
+
}
|
31
|
+
}
|
32
|
+
```
|
33
|
+
|
34
|
+
or if it returns a collection:
|
35
|
+
|
36
|
+
```json
|
37
|
+
{
|
38
|
+
"posts": [
|
39
|
+
{
|
40
|
+
"id": 1,
|
41
|
+
"title": "Awesome Post Tile",
|
42
|
+
"content": "Post content"
|
43
|
+
},
|
44
|
+
{
|
45
|
+
"id": 2,
|
46
|
+
"title": "Another Post Tile",
|
47
|
+
"content": "Another post content"
|
48
|
+
}
|
49
|
+
]
|
50
|
+
}
|
51
|
+
```
|
@@ -0,0 +1,42 @@
|
|
1
|
+
## Using AMS Outside Of A Controller
|
2
|
+
|
3
|
+
### Serializing a resource
|
4
|
+
|
5
|
+
In AMS versions 0.10 or later, serializing resources outside of the controller context is fairly simple:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
# Create our resource
|
9
|
+
post = Post.create(title: "Sample post", body: "I love Active Model Serializers!")
|
10
|
+
|
11
|
+
# Optional options parameters
|
12
|
+
options = {}
|
13
|
+
|
14
|
+
# Create a serializable resource instance
|
15
|
+
serializable_resource = ActiveModel::SerializableResource.new(post, options)
|
16
|
+
|
17
|
+
# Convert your resource into json
|
18
|
+
model_json = serializable_resource.as_json
|
19
|
+
```
|
20
|
+
|
21
|
+
### Retrieving a Resource's Active Model Serializer
|
22
|
+
|
23
|
+
If you want to retrieve a serializer for a specific resource, you can do the following:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
# Create our resource
|
27
|
+
post = Post.create(title: "Another Example", body: "So much fun.")
|
28
|
+
|
29
|
+
# Optional options parameters
|
30
|
+
options = {}
|
31
|
+
|
32
|
+
# Retrieve the default serializer for posts
|
33
|
+
serializer = ActiveModel::Serializer.serializer_for(post, options)
|
34
|
+
```
|
35
|
+
|
36
|
+
You could also retrieve the serializer via:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
ActiveModel::SerializableResource.new(post, options).serializer
|
40
|
+
```
|
41
|
+
|
42
|
+
Both approaches will return an instance, if any, of the resource's serializer.
|
@@ -1,32 +1,14 @@
|
|
1
|
+
require 'active_support/core_ext/class/attribute'
|
2
|
+
|
1
3
|
module ActionController
|
2
|
-
# Action Controller Serialization
|
3
|
-
#
|
4
|
-
# Overrides render :json to check if the given object implements +active_model_serializer+
|
5
|
-
# as a method. If so, use the returned serializer instead of calling +to_json+ on the object.
|
6
|
-
#
|
7
|
-
# This module also provides a serialization_scope method that allows you to configure the
|
8
|
-
# +serialization_scope+ of the serializer. Most apps will likely set the +serialization_scope+
|
9
|
-
# to the current user:
|
10
|
-
#
|
11
|
-
# class ApplicationController < ActionController::Base
|
12
|
-
# serialization_scope :current_user
|
13
|
-
# end
|
14
|
-
#
|
15
|
-
# If you need more complex scope rules, you can simply override the serialization_scope:
|
16
|
-
#
|
17
|
-
# class ApplicationController < ActionController::Base
|
18
|
-
# private
|
19
|
-
#
|
20
|
-
# def serialization_scope
|
21
|
-
# current_user
|
22
|
-
# end
|
23
|
-
# end
|
24
|
-
#
|
25
4
|
module Serialization
|
26
5
|
extend ActiveSupport::Concern
|
27
6
|
|
28
7
|
include ActionController::Renderers
|
29
8
|
|
9
|
+
# Deprecated
|
10
|
+
ADAPTER_OPTION_KEYS = ActiveModel::SerializableResource::ADAPTER_OPTION_KEYS
|
11
|
+
|
30
12
|
included do
|
31
13
|
class_attribute :_serialization_scope
|
32
14
|
self._serialization_scope = :current_user
|
@@ -37,18 +19,36 @@ module ActionController
|
|
37
19
|
respond_to?(_serialization_scope, true)
|
38
20
|
end
|
39
21
|
|
40
|
-
def
|
22
|
+
def get_serializer(resource, options = {})
|
23
|
+
if !use_adapter?
|
24
|
+
warn 'ActionController::Serialization#use_adapter? has been removed. '\
|
25
|
+
"Please pass 'adapter: false' or see ActiveSupport::SerializableResource.new"
|
26
|
+
options[:adapter] = false
|
27
|
+
end
|
28
|
+
serializable_resource = ActiveModel::SerializableResource.new(resource, options)
|
29
|
+
if serializable_resource.serializer?
|
30
|
+
serializable_resource.serialization_scope ||= serialization_scope
|
31
|
+
serializable_resource.serialization_scope_name = _serialization_scope
|
32
|
+
begin
|
33
|
+
serializable_resource.adapter
|
34
|
+
rescue ActiveModel::Serializer::ArraySerializer::NoSerializerError
|
35
|
+
resource
|
36
|
+
end
|
37
|
+
else
|
38
|
+
resource
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Deprecated
|
43
|
+
def use_adapter?
|
44
|
+
true
|
41
45
|
end
|
42
46
|
|
43
47
|
[:_render_option_json, :_render_with_renderer_json].each do |renderer_method|
|
44
48
|
define_method renderer_method do |resource, options|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
super(json, options)
|
49
|
-
else
|
50
|
-
super(resource, options)
|
51
|
-
end
|
49
|
+
options.fetch(:context) { options[:context] = request }
|
50
|
+
serializable_resource = get_serializer(resource, options)
|
51
|
+
super(serializable_resource, options)
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|