active_model_serializers 0.8.3 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE.md +29 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +15 -0
- data/.gitignore +17 -0
- data/.rubocop.yml +104 -0
- data/.rubocop_todo.yml +167 -0
- data/.simplecov +110 -0
- data/.travis.yml +39 -24
- data/CHANGELOG.md +465 -6
- data/CONTRIBUTING.md +105 -0
- data/Gemfile +50 -1
- data/{MIT-LICENSE.txt → MIT-LICENSE} +3 -2
- data/README.md +102 -590
- data/Rakefile +93 -8
- data/active_model_serializers.gemspec +65 -23
- data/appveyor.yml +24 -0
- data/bin/bench +171 -0
- data/bin/bench_regression +316 -0
- data/bin/serve_benchmark +39 -0
- data/docs/ARCHITECTURE.md +126 -0
- data/docs/README.md +40 -0
- data/docs/STYLE.md +58 -0
- data/docs/general/adapters.md +245 -0
- data/docs/general/caching.md +52 -0
- data/docs/general/configuration_options.md +100 -0
- data/docs/general/deserialization.md +100 -0
- data/docs/general/getting_started.md +133 -0
- data/docs/general/instrumentation.md +40 -0
- data/docs/general/key_transforms.md +40 -0
- data/docs/general/logging.md +14 -0
- data/docs/general/rendering.md +255 -0
- data/docs/general/serializers.md +372 -0
- data/docs/how-open-source-maintained.jpg +0 -0
- data/docs/howto/add_pagination_links.md +139 -0
- data/docs/howto/add_root_key.md +51 -0
- data/docs/howto/outside_controller_use.md +58 -0
- data/docs/howto/passing_arbitrary_options.md +27 -0
- data/docs/howto/serialize_poro.md +32 -0
- data/docs/howto/test.md +152 -0
- data/docs/integrations/ember-and-json-api.md +112 -0
- data/docs/integrations/grape.md +19 -0
- data/docs/jsonapi/errors.md +56 -0
- data/docs/jsonapi/schema/schema.json +366 -0
- data/docs/jsonapi/schema.md +151 -0
- data/docs/rfcs/0000-namespace.md +106 -0
- data/docs/rfcs/template.md +15 -0
- data/lib/action_controller/serialization.rb +31 -36
- data/lib/active_model/serializable_resource.rb +11 -0
- data/lib/active_model/serializer/adapter/attributes.rb +15 -0
- data/lib/active_model/serializer/adapter/base.rb +16 -0
- data/lib/active_model/serializer/adapter/json.rb +15 -0
- data/lib/active_model/serializer/adapter/json_api.rb +15 -0
- data/lib/active_model/serializer/adapter/null.rb +15 -0
- data/lib/active_model/serializer/adapter.rb +24 -0
- data/lib/active_model/serializer/array_serializer.rb +9 -0
- data/lib/active_model/serializer/association.rb +19 -0
- data/lib/active_model/serializer/associations.rb +87 -220
- data/lib/active_model/serializer/attribute.rb +25 -0
- data/lib/active_model/serializer/attributes.rb +82 -0
- data/lib/active_model/serializer/belongs_to_reflection.rb +10 -0
- data/lib/active_model/serializer/caching.rb +333 -0
- data/lib/active_model/serializer/collection_reflection.rb +7 -0
- data/lib/active_model/serializer/collection_serializer.rb +64 -0
- data/lib/active_model/serializer/configuration.rb +35 -0
- data/lib/active_model/serializer/error_serializer.rb +10 -0
- data/lib/active_model/serializer/errors_serializer.rb +27 -0
- data/lib/active_model/serializer/field.rb +90 -0
- data/lib/active_model/serializer/fieldset.rb +31 -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/include_tree.rb +111 -0
- data/lib/active_model/serializer/links.rb +35 -0
- data/lib/active_model/serializer/lint.rb +146 -0
- data/lib/active_model/serializer/meta.rb +29 -0
- data/lib/active_model/serializer/null.rb +17 -0
- data/lib/active_model/serializer/reflection.rb +147 -0
- data/lib/active_model/serializer/singular_reflection.rb +7 -0
- data/lib/active_model/serializer/type.rb +25 -0
- data/lib/active_model/{serializers → serializer}/version.rb +1 -1
- data/lib/active_model/serializer.rb +158 -481
- data/lib/active_model_serializers/adapter/attributes.rb +76 -0
- data/lib/active_model_serializers/adapter/base.rb +83 -0
- data/lib/active_model_serializers/adapter/json.rb +21 -0
- data/lib/active_model_serializers/adapter/json_api/deserialization.rb +213 -0
- data/lib/active_model_serializers/adapter/json_api/error.rb +96 -0
- data/lib/active_model_serializers/adapter/json_api/jsonapi.rb +49 -0
- data/lib/active_model_serializers/adapter/json_api/link.rb +83 -0
- data/lib/active_model_serializers/adapter/json_api/meta.rb +37 -0
- data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +62 -0
- data/lib/active_model_serializers/adapter/json_api/relationship.rb +52 -0
- data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +37 -0
- data/lib/active_model_serializers/adapter/json_api.rb +516 -0
- data/lib/active_model_serializers/adapter/null.rb +9 -0
- data/lib/active_model_serializers/adapter.rb +92 -0
- data/lib/active_model_serializers/callbacks.rb +55 -0
- data/lib/active_model_serializers/deprecate.rb +55 -0
- data/lib/active_model_serializers/deserialization.rb +13 -0
- data/lib/active_model_serializers/json_pointer.rb +14 -0
- data/lib/active_model_serializers/key_transform.rb +70 -0
- data/lib/active_model_serializers/logging.rb +122 -0
- data/lib/active_model_serializers/model.rb +49 -0
- data/lib/active_model_serializers/railtie.rb +46 -0
- data/lib/active_model_serializers/register_jsonapi_renderer.rb +65 -0
- data/lib/active_model_serializers/serializable_resource.rb +81 -0
- data/lib/active_model_serializers/serialization_context.rb +32 -0
- data/lib/active_model_serializers/test/schema.rb +138 -0
- data/lib/active_model_serializers/test/serializer.rb +125 -0
- data/lib/active_model_serializers/test.rb +7 -0
- data/lib/active_model_serializers.rb +32 -89
- data/lib/generators/rails/USAGE +6 -0
- data/lib/generators/rails/resource_override.rb +10 -0
- data/lib/generators/rails/serializer_generator.rb +36 -0
- data/lib/generators/rails/templates/serializer.rb.erb +8 -0
- data/lib/grape/active_model_serializers.rb +14 -0
- data/lib/grape/formatters/active_model_serializers.rb +15 -0
- data/lib/grape/helpers/active_model_serializers.rb +16 -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/include_test.rb +167 -0
- data/test/action_controller/json_api/deserialization_test.rb +112 -0
- data/test/action_controller/json_api/errors_test.rb +41 -0
- data/test/action_controller/json_api/linked_test.rb +197 -0
- data/test/action_controller/json_api/pagination_test.rb +116 -0
- data/test/action_controller/json_api/transform_test.rb +181 -0
- data/test/action_controller/serialization_scope_name_test.rb +229 -0
- data/test/action_controller/serialization_test.rb +469 -0
- data/test/active_model_serializers/adapter_for_test.rb +208 -0
- data/test/active_model_serializers/json_pointer_test.rb +20 -0
- data/test/active_model_serializers/key_transform_test.rb +263 -0
- data/test/active_model_serializers/logging_test.rb +77 -0
- data/test/active_model_serializers/model_test.rb +9 -0
- data/test/active_model_serializers/railtie_test_isolated.rb +63 -0
- data/test/active_model_serializers/serialization_context_test_isolated.rb +58 -0
- data/test/active_model_serializers/test/schema_test.rb +130 -0
- data/test/active_model_serializers/test/serializer_test.rb +62 -0
- data/test/active_record_test.rb +9 -0
- data/test/adapter/deprecation_test.rb +100 -0
- data/test/adapter/json/belongs_to_test.rb +45 -0
- data/test/adapter/json/collection_test.rb +90 -0
- data/test/adapter/json/has_many_test.rb +45 -0
- data/test/adapter/json/transform_test.rb +93 -0
- data/test/adapter/json_api/belongs_to_test.rb +155 -0
- data/test/adapter/json_api/collection_test.rb +95 -0
- data/test/adapter/json_api/errors_test.rb +78 -0
- data/test/adapter/json_api/fields_test.rb +87 -0
- data/test/adapter/json_api/has_many_embed_ids_test.rb +43 -0
- data/test/adapter/json_api/has_many_explicit_serializer_test.rb +96 -0
- data/test/adapter/json_api/has_many_test.rb +144 -0
- data/test/adapter/json_api/has_one_test.rb +80 -0
- data/test/adapter/json_api/json_api_test.rb +35 -0
- data/test/adapter/json_api/linked_test.rb +392 -0
- data/test/adapter/json_api/links_test.rb +93 -0
- data/test/adapter/json_api/pagination_links_test.rb +166 -0
- data/test/adapter/json_api/parse_test.rb +137 -0
- data/test/adapter/json_api/relationship_test.rb +161 -0
- data/test/adapter/json_api/relationships_test.rb +199 -0
- data/test/adapter/json_api/resource_identifier_test.rb +85 -0
- data/test/adapter/json_api/resource_meta_test.rb +100 -0
- data/test/adapter/json_api/toplevel_jsonapi_test.rb +82 -0
- data/test/adapter/json_api/transform_test.rb +502 -0
- data/test/adapter/json_api/type_test.rb +61 -0
- data/test/adapter/json_test.rb +45 -0
- data/test/adapter/null_test.rb +23 -0
- data/test/adapter/polymorphic_test.rb +171 -0
- data/test/adapter_test.rb +67 -0
- data/test/array_serializer_test.rb +20 -73
- data/test/benchmark/app.rb +65 -0
- data/test/benchmark/benchmarking_support.rb +67 -0
- data/test/benchmark/bm_caching.rb +119 -0
- data/test/benchmark/bm_transform.rb +34 -0
- data/test/benchmark/config.ru +3 -0
- data/test/benchmark/controllers.rb +84 -0
- data/test/benchmark/fixtures.rb +219 -0
- data/test/cache_test.rb +485 -0
- data/test/collection_serializer_test.rb +110 -0
- data/test/fixtures/active_record.rb +78 -0
- data/test/fixtures/poro.rb +282 -0
- data/test/generators/scaffold_controller_generator_test.rb +24 -0
- data/test/generators/serializer_generator_test.rb +57 -0
- data/test/grape_test.rb +82 -0
- data/test/include_tree/from_include_args_test.rb +26 -0
- data/test/include_tree/from_string_test.rb +94 -0
- data/test/include_tree/include_args_to_hash_test.rb +64 -0
- data/test/lint_test.rb +49 -0
- data/test/logger_test.rb +18 -0
- data/test/poro_test.rb +9 -0
- data/test/serializable_resource_test.rb +83 -0
- data/test/serializers/association_macros_test.rb +36 -0
- data/test/serializers/associations_test.rb +295 -0
- data/test/serializers/attribute_test.rb +151 -0
- data/test/serializers/attributes_test.rb +52 -0
- data/test/serializers/caching_configuration_test_isolated.rb +170 -0
- data/test/serializers/configuration_test.rb +32 -0
- data/test/serializers/fieldset_test.rb +14 -0
- data/test/serializers/meta_test.rb +196 -0
- data/test/serializers/options_test.rb +21 -0
- data/test/serializers/read_attribute_for_serialization_test.rb +79 -0
- data/test/serializers/root_test.rb +21 -0
- data/test/serializers/serialization_test.rb +55 -0
- data/test/serializers/serializer_for_test.rb +134 -0
- data/test/support/custom_schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
- data/test/support/isolated_unit.rb +79 -0
- data/test/support/rails5_shims.rb +47 -0
- data/test/support/rails_app.rb +45 -0
- data/test/support/schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
- data/test/support/schemas/active_model_serializers/test/schema_test/my/show.json +6 -0
- data/test/support/schemas/custom/show.json +7 -0
- data/test/support/schemas/hyper_schema.json +93 -0
- data/test/support/schemas/render_using_json_api.json +43 -0
- data/test/support/schemas/simple_json_pointers.json +10 -0
- data/test/support/serialization_testing.rb +53 -0
- data/test/test_helper.rb +48 -23
- metadata +449 -43
- 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/USAGE +0 -9
- data/lib/generators/serializer/serializer_generator.rb +0 -42
- 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_scope_name_test.rb +0 -67
- 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
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
[Back to Guides](../README.md)
|
|
2
|
+
|
|
3
|
+
# How to add pagination links
|
|
4
|
+
|
|
5
|
+
### JSON API adapter
|
|
6
|
+
|
|
7
|
+
Pagination links will be included in your response automatically as long as
|
|
8
|
+
the resource is paginated and if you are using the ```JsonApi``` adapter.
|
|
9
|
+
|
|
10
|
+
If you want pagination links in your response, use [Kaminari](https://github.com/amatsuda/kaminari)
|
|
11
|
+
or [WillPaginate](https://github.com/mislav/will_paginate).
|
|
12
|
+
|
|
13
|
+
Although the others adapters does not have this feature, it is possible to
|
|
14
|
+
implement pagination links to `JSON` adapter. For more information about it,
|
|
15
|
+
please see in our docs
|
|
16
|
+
|
|
17
|
+
###### Kaminari examples
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
#array
|
|
21
|
+
@posts = Kaminari.paginate_array([1, 2, 3]).page(3).per(1)
|
|
22
|
+
render json: @posts
|
|
23
|
+
|
|
24
|
+
#active_record
|
|
25
|
+
@posts = Post.page(3).per(1)
|
|
26
|
+
render json: @posts
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
###### WillPaginate examples
|
|
30
|
+
|
|
31
|
+
```ruby
|
|
32
|
+
#array
|
|
33
|
+
@posts = [1,2,3].paginate(page: 3, per_page: 1)
|
|
34
|
+
render json: @posts
|
|
35
|
+
|
|
36
|
+
#active_record
|
|
37
|
+
@posts = Post.page(3).per_page(1)
|
|
38
|
+
render json: @posts
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
ActiveModelSerializers.config.adapter = :json_api
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
ex:
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"data": [
|
|
49
|
+
{
|
|
50
|
+
"type": "articles",
|
|
51
|
+
"id": "3",
|
|
52
|
+
"attributes": {
|
|
53
|
+
"title": "JSON API paints my bikeshed!",
|
|
54
|
+
"body": "The shortest article. Ever.",
|
|
55
|
+
"created": "2015-05-22T14:56:29.000Z",
|
|
56
|
+
"updated": "2015-05-22T14:56:28.000Z"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"links": {
|
|
61
|
+
"self": "http://example.com/articles?page[number]=3&page[size]=1",
|
|
62
|
+
"first": "http://example.com/articles?page[number]=1&page[size]=1",
|
|
63
|
+
"prev": "http://example.com/articles?page[number]=2&page[size]=1",
|
|
64
|
+
"next": "http://example.com/articles?page[number]=4&page[size]=1",
|
|
65
|
+
"last": "http://example.com/articles?page[number]=13&page[size]=1"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
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).
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
### JSON adapter
|
|
74
|
+
|
|
75
|
+
If you are using `JSON` adapter, pagination links will not be included automatically, but it is possible to do so using `meta` key.
|
|
76
|
+
|
|
77
|
+
Add this method to your base API controller.
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
def pagination_dict(object)
|
|
81
|
+
{
|
|
82
|
+
current_page: object.current_page,
|
|
83
|
+
next_page: object.next_page,
|
|
84
|
+
prev_page: object.prev_page,
|
|
85
|
+
total_pages: object.total_pages,
|
|
86
|
+
total_count: object.total_count
|
|
87
|
+
}
|
|
88
|
+
end
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Then, use it on your render method.
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
render json: posts, meta: pagination_dict(posts)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
ex.
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"posts": [
|
|
101
|
+
{
|
|
102
|
+
"id": 2,
|
|
103
|
+
"title": "JSON API paints my bikeshed!",
|
|
104
|
+
"body": "The shortest article. Ever."
|
|
105
|
+
}
|
|
106
|
+
],
|
|
107
|
+
"meta": {
|
|
108
|
+
"current_page": 3,
|
|
109
|
+
"next_page": 4,
|
|
110
|
+
"prev_page": 2,
|
|
111
|
+
"total_pages": 10,
|
|
112
|
+
"total_count": 10
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
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.
|
|
118
|
+
|
|
119
|
+
```ruby
|
|
120
|
+
render json: @posts, each_serializer: PostPreviewSerializer, meta: meta_attributes(@post)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
```ruby
|
|
124
|
+
#expects pagination!
|
|
125
|
+
def meta_attributes(resource, extra_meta = {})
|
|
126
|
+
{
|
|
127
|
+
current_page: resource.current_page,
|
|
128
|
+
next_page: resource.next_page,
|
|
129
|
+
prev_page: resource.prev_page,
|
|
130
|
+
total_pages: resource.total_pages,
|
|
131
|
+
total_count: resource.total_count
|
|
132
|
+
}.merge(extra_meta)
|
|
133
|
+
end
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
### Attributes adapter
|
|
138
|
+
|
|
139
|
+
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 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:
|
|
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
|
+
ActiveModelSerializers.config.adapter = :json
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
You can also specify a class as adapter, as long as it complies with the ActiveModelSerializers 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,58 @@
|
|
|
1
|
+
[Back to Guides](../README.md)
|
|
2
|
+
|
|
3
|
+
## Using ActiveModelSerializers Outside Of A Controller
|
|
4
|
+
|
|
5
|
+
### Serializing a resource
|
|
6
|
+
|
|
7
|
+
In ActiveModelSerializers versions 0.10 or later, serializing resources outside of the controller context is fairly simple:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
# Create our resource
|
|
11
|
+
post = Post.create(title: "Sample post", body: "I love Active Model Serializers!")
|
|
12
|
+
|
|
13
|
+
# Optional options parameters
|
|
14
|
+
options = {}
|
|
15
|
+
|
|
16
|
+
# Create a serializable resource instance
|
|
17
|
+
serializable_resource = ActiveModelSerializers::SerializableResource.new(post, options)
|
|
18
|
+
|
|
19
|
+
# Convert your resource into json
|
|
20
|
+
model_json = serializable_resource.as_json
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Looking up the Serializer for a Resource
|
|
24
|
+
|
|
25
|
+
If you want to retrieve a serializer for a specific resource, you can do the following:
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
# Create our resource
|
|
29
|
+
post = Post.create(title: "Another Example", body: "So much fun.")
|
|
30
|
+
|
|
31
|
+
# Optional options parameters
|
|
32
|
+
options = {}
|
|
33
|
+
|
|
34
|
+
# Retrieve the default serializer for posts
|
|
35
|
+
serializer = ActiveModel::Serializer.serializer_for(post, options)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
You could also retrieve the serializer via:
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
ActiveModelSerializers::SerializableResource.new(post, options).serializer
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Both approaches will return an instance, if any, of the resource's serializer.
|
|
45
|
+
|
|
46
|
+
## Serializing before controller render
|
|
47
|
+
|
|
48
|
+
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
|
|
49
|
+
the resource you want to be serialized and call `.as_json`.
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
def create
|
|
53
|
+
message = current_user.messages.create!(message_params)
|
|
54
|
+
message_json = ActiveModelSerializers::SerializableResource.new(message).as_json
|
|
55
|
+
MessageCreationWorker.perform(message_json)
|
|
56
|
+
head 204
|
|
57
|
+
end
|
|
58
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[Back to Guides](../README.md)
|
|
2
|
+
|
|
3
|
+
# Passing Arbitrary Options To A Serializer
|
|
4
|
+
|
|
5
|
+
In addition to the [`serialization_scope`](../general/serializers.md#scope), any options passed to `render`
|
|
6
|
+
that are not reserved for the [adapter](../general/rendering.md#adapter_opts)
|
|
7
|
+
are available in the serializer as [instance_options](../general/serializers.md#instance_options).
|
|
8
|
+
|
|
9
|
+
For example, we could pass in a field, such as `user_id` into our serializer.
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
# posts_controller.rb
|
|
13
|
+
class PostsController < ApplicationController
|
|
14
|
+
def dashboard
|
|
15
|
+
render json: @post, user_id: 12
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# post_serializer.rb
|
|
20
|
+
class PostSerializer < ActiveModel::Serializer
|
|
21
|
+
attributes :id, :title, :body
|
|
22
|
+
|
|
23
|
+
def comments_by_me
|
|
24
|
+
Comments.where(user_id: instance_options[:user_id], post_id: object.id)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[Back to Guides](../README.md)
|
|
2
|
+
|
|
3
|
+
# How to serialize a Plain-Old Ruby Object (PORO)
|
|
4
|
+
|
|
5
|
+
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:
|
|
6
|
+
```ruby
|
|
7
|
+
# my_model.rb
|
|
8
|
+
class MyModel
|
|
9
|
+
alias :read_attribute_for_serialization :send
|
|
10
|
+
attr_accessor :id, :name, :level
|
|
11
|
+
|
|
12
|
+
def initialize(attributes)
|
|
13
|
+
@id = attributes[:id]
|
|
14
|
+
@name = attributes[:name]
|
|
15
|
+
@level = attributes[:level]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.model_name
|
|
19
|
+
@_model_name ||= ActiveModel::Name.new(self)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Fortunately, ActiveModelSerializers provides a [`ActiveModelSerializers::Model`](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model_serializers/model.rb) which you can use in production code that will make your PORO a lot cleaner. The above code now becomes:
|
|
25
|
+
```ruby
|
|
26
|
+
# my_model.rb
|
|
27
|
+
class MyModel < ActiveModelSerializers::Model
|
|
28
|
+
attr_accessor :id, :name, :level
|
|
29
|
+
end
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The default serializer would be `MyModelSerializer`.
|
data/docs/howto/test.md
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# How to test
|
|
2
|
+
|
|
3
|
+
## Controller Serializer Usage
|
|
4
|
+
|
|
5
|
+
ActiveModelSerializers provides a `assert_serializer` method to be used on your controller tests to
|
|
6
|
+
assert that a specific serializer was used.
|
|
7
|
+
|
|
8
|
+
```ruby
|
|
9
|
+
class PostsControllerTest < ActionController::TestCase
|
|
10
|
+
test "should render post serializer" do
|
|
11
|
+
get :index
|
|
12
|
+
assert_serializer "PostSerializer"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
See [ActiveModelSerializers::Test::Serializer](../../lib/active_model_serializers/test/serializer.rb)
|
|
18
|
+
for more examples and documentation.
|
|
19
|
+
|
|
20
|
+
## Serialization against a schema
|
|
21
|
+
|
|
22
|
+
### Dependencies
|
|
23
|
+
|
|
24
|
+
To use the `assert_response_schema` you need to have the
|
|
25
|
+
[`json_schema`](https://github.com/brandur/json_schema) on your Gemfile. Please
|
|
26
|
+
add it to your Gemfile and run `$ bundle install`.
|
|
27
|
+
|
|
28
|
+
### Minitest test helpers
|
|
29
|
+
|
|
30
|
+
ActiveModelSerializers provides a `assert_response_schema` method to be used on your controller tests to
|
|
31
|
+
assert the response against a [JSON Schema](http://json-schema.org/). Let's take
|
|
32
|
+
a look in an example.
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
class PostsController < ApplicationController
|
|
36
|
+
def show
|
|
37
|
+
@post = Post.find(params[:id])
|
|
38
|
+
|
|
39
|
+
render json: @post
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
To test the `posts#show` response of this controller we need to create a file
|
|
45
|
+
named `test/support/schemas/posts/show.json`. The helper uses a naming convention
|
|
46
|
+
to locate the file.
|
|
47
|
+
|
|
48
|
+
This file is a JSON Schema representation of our response.
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"properties": {
|
|
53
|
+
"title" : { "type" : "string" },
|
|
54
|
+
"content" : { "type" : "string" }
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
With all in place we can go to our test and use the helper.
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
class PostsControllerTest < ActionController::TestCase
|
|
63
|
+
test "should render right response" do
|
|
64
|
+
get :index
|
|
65
|
+
assert_response_schema
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
#### Load a custom schema
|
|
71
|
+
|
|
72
|
+
If we need to use another schema, for example when we have a namespaced API that
|
|
73
|
+
shows the same response, we can pass the path of the schema.
|
|
74
|
+
|
|
75
|
+
```ruby
|
|
76
|
+
module V1
|
|
77
|
+
class PostsController < ApplicationController
|
|
78
|
+
def show
|
|
79
|
+
@post = Post.find(params[:id])
|
|
80
|
+
|
|
81
|
+
render json: @post
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
class V1::PostsControllerTest < ActionController::TestCase
|
|
89
|
+
test "should render right response" do
|
|
90
|
+
get :index
|
|
91
|
+
assert_response_schema('posts/show.json')
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
#### Change the schema path
|
|
97
|
+
|
|
98
|
+
By default all schemas are created at `test/support/schemas`. If we are using
|
|
99
|
+
RSpec for example we can change this to `spec/support/schemas` defining the
|
|
100
|
+
default schema path in an initializer.
|
|
101
|
+
|
|
102
|
+
```ruby
|
|
103
|
+
ActiveModelSerializers.config.schema_path = 'spec/support/schemas'
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### Using with the Heroku’s JSON Schema-based tools
|
|
107
|
+
|
|
108
|
+
To use the test helper with the [prmd](https://github.com/interagent/prmd) and
|
|
109
|
+
[committee](https://github.com/interagent/committee).
|
|
110
|
+
|
|
111
|
+
We need to change the schema path to the recommended by prmd:
|
|
112
|
+
|
|
113
|
+
```ruby
|
|
114
|
+
ActiveModelSerializers.config.schema_path = 'docs/schema/schemata'
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
We also need to structure our schemata according to Heroku's conventions
|
|
118
|
+
(e.g. including
|
|
119
|
+
[required metadata](https://github.com/interagent/prmd/blob/master/docs/schemata.md#meta-data)
|
|
120
|
+
and [links](https://github.com/interagent/prmd/blob/master/docs/schemata.md#links).
|
|
121
|
+
|
|
122
|
+
#### JSON Pointers
|
|
123
|
+
|
|
124
|
+
If we plan to use [JSON
|
|
125
|
+
Pointers](http://spacetelescope.github.io/understanding-json-schema/UnderstandingJSONSchema.pdf) we need to define the `id` attribute on the schema. Example:
|
|
126
|
+
|
|
127
|
+
```js
|
|
128
|
+
// attributes.json
|
|
129
|
+
|
|
130
|
+
{
|
|
131
|
+
"id": "file://attributes.json#",
|
|
132
|
+
"properties": {
|
|
133
|
+
"name" : { "type" : "string" },
|
|
134
|
+
"description" : { "type" : "string" }
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
```js
|
|
140
|
+
// show.json
|
|
141
|
+
|
|
142
|
+
{
|
|
143
|
+
"properties": {
|
|
144
|
+
"name": {
|
|
145
|
+
"$ref": "file://attributes.json#/properties/name"
|
|
146
|
+
},
|
|
147
|
+
"description": {
|
|
148
|
+
"$ref": "file://attributes.json#/properties/description"
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
[Back to Guides](../README.md)
|
|
2
|
+
|
|
3
|
+
# Integrating with Ember and JSON API
|
|
4
|
+
|
|
5
|
+
- [Preparation](./ember-and-json-api.md#preparation)
|
|
6
|
+
- [Server-Side Changes](./ember-and-json-api.md#server-side-changes)
|
|
7
|
+
- [Adapter Changes](./ember-and-json-api.md#adapter-changes)
|
|
8
|
+
- [Serializer Changes](./ember-and-json-api.md#serializer-changes)
|
|
9
|
+
- [Including Nested Resources](./ember-and-json-api.md#including-nested-resources)
|
|
10
|
+
|
|
11
|
+
## Preparation
|
|
12
|
+
|
|
13
|
+
Note: This guide assumes that `ember-cli` is used for your ember app.
|
|
14
|
+
|
|
15
|
+
The JSON API specification calls for hyphens for multi-word separators. ActiveModelSerializers uses underscores.
|
|
16
|
+
To solve this, in Ember, both the adapter and the serializer will need some modifications:
|
|
17
|
+
|
|
18
|
+
### Server-Side Changes
|
|
19
|
+
|
|
20
|
+
there are multiple mimetypes for json that should all be parsed similarly, so
|
|
21
|
+
in `config/initializers/mime_types.rb`:
|
|
22
|
+
```ruby
|
|
23
|
+
api_mime_types = %W(
|
|
24
|
+
application/vnd.api+json
|
|
25
|
+
text/x-json
|
|
26
|
+
application/json
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
Mime::Type.unregister :json
|
|
30
|
+
Mime::Type.register 'application/json', :json, api_mime_types
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Adapter Changes
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
// app/adapters/application.js
|
|
37
|
+
import DS from 'ember-data';
|
|
38
|
+
import ENV from "../config/environment";
|
|
39
|
+
|
|
40
|
+
export default DS.JSONAPIAdapter.extend({
|
|
41
|
+
namespace: 'api',
|
|
42
|
+
// if your rails app is on a different port from your ember app
|
|
43
|
+
// this can be helpful for development.
|
|
44
|
+
// in production, the host for both rails and ember should be the same.
|
|
45
|
+
host: ENV.host,
|
|
46
|
+
|
|
47
|
+
// allows the multiword paths in urls to be underscored
|
|
48
|
+
pathForType: function(type) {
|
|
49
|
+
let underscored = Ember.String.underscore(type);
|
|
50
|
+
return Ember.String.pluralize(underscored);
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
// allows queries to be sent along with a findRecord
|
|
54
|
+
// hopefully Ember / EmberData will soon have this built in
|
|
55
|
+
// ember-data issue tracked here:
|
|
56
|
+
// https://github.com/emberjs/data/issues/3596
|
|
57
|
+
urlForFindRecord(id, modelName, snapshot) {
|
|
58
|
+
let url = this._super(...arguments);
|
|
59
|
+
let query = Ember.get(snapshot, 'adapterOptions.query');
|
|
60
|
+
if(query) {
|
|
61
|
+
url += '?' + Ember.$.param(query);
|
|
62
|
+
}
|
|
63
|
+
return url;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Serializer Changes
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
// app/serializers/application.js
|
|
72
|
+
import Ember from 'ember';
|
|
73
|
+
import DS from 'ember-data';
|
|
74
|
+
var underscore = Ember.String.underscore;
|
|
75
|
+
|
|
76
|
+
export default DS.JSONAPISerializer.extend({
|
|
77
|
+
keyForAttribute: function(attr) {
|
|
78
|
+
return underscore(attr);
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
keyForRelationship: function(rawKey) {
|
|
82
|
+
return underscore(rawKey);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Including Nested Resources
|
|
89
|
+
|
|
90
|
+
Previously, `store.find` and `store.findRecord` did not allow specification of any query params.
|
|
91
|
+
The ActiveModelSerializers default for the `include` parameter is to be `nil` meaning that if any associations are defined in your serializer, only the `id` and `type` will be in the `relationships` structure of the JSON API response.
|
|
92
|
+
For more on `include` usage, see: [The JSON API include examples](./../general/adapters.md#JSON-API)
|
|
93
|
+
|
|
94
|
+
With the above modifications, you can execute code as below in order to include nested resources while doing a find query.
|
|
95
|
+
|
|
96
|
+
```javascript
|
|
97
|
+
store.findRecord('post', postId, { adapterOptions: { query: { include: 'comments' } } });
|
|
98
|
+
```
|
|
99
|
+
will generate the path `/posts/{postId}?include='comments'`
|
|
100
|
+
|
|
101
|
+
So then in your controller, you'll want to be sure to have something like:
|
|
102
|
+
```ruby
|
|
103
|
+
render json: @post, include: params[:include]
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
If you want to use `include` on a collection, you'd write something like this:
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
store.query('post', { include: 'comments' });
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
which will generate the path `/posts?include='comments'`
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Integration with Grape
|
|
2
|
+
|
|
3
|
+
[Grape](https://github.com/ruby-grape/grape) is an opinionated micro-framework for creating REST-like APIs in ruby.
|
|
4
|
+
|
|
5
|
+
ActiveModelSerializers currently supports Grape >= 0.13, < 1.0
|
|
6
|
+
|
|
7
|
+
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:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
module Example
|
|
11
|
+
class Dummy < Grape::API
|
|
12
|
+
require 'grape/active_model_serializers'
|
|
13
|
+
include Grape::ActiveModelSerializers
|
|
14
|
+
mount Example::V1::Base
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Aside from this, [configuration](../general/configuration_options.md) of ActiveModelSerializers is exactly the same.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
[Back to Guides](../README.md)
|
|
2
|
+
|
|
3
|
+
# [JSON API Errors](http://jsonapi.org/format/#errors)
|
|
4
|
+
|
|
5
|
+
Rendering error documents requires specifying the error serializer(s):
|
|
6
|
+
|
|
7
|
+
- Serializer:
|
|
8
|
+
- For a single resource: `serializer: ActiveModel::Serializer::ErrorSerializer`.
|
|
9
|
+
- For a collection: `serializer: ActiveModel::Serializer::ErrorsSerializer`, `each_serializer: ActiveModel::Serializer::ErrorSerializer`.
|
|
10
|
+
|
|
11
|
+
The resource **MUST** have a non-empty associated `#errors` object.
|
|
12
|
+
The `errors` object must have a `#messages` method that returns a hash of error name to array of
|
|
13
|
+
descriptions.
|
|
14
|
+
|
|
15
|
+
## Use in controllers
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
resource = Profile.new(name: 'Name 1',
|
|
19
|
+
description: 'Description 1',
|
|
20
|
+
comments: 'Comments 1')
|
|
21
|
+
resource.errors.add(:name, 'cannot be nil')
|
|
22
|
+
resource.errors.add(:name, 'must be longer')
|
|
23
|
+
resource.errors.add(:id, 'must be a uuid')
|
|
24
|
+
|
|
25
|
+
render json: resource, status: 422, adapter: :json_api, serializer: ActiveModel::Serializer::ErrorSerializer
|
|
26
|
+
# #=>
|
|
27
|
+
# { :errors =>
|
|
28
|
+
# [
|
|
29
|
+
# { :source => { :pointer => '/data/attributes/name' }, :detail => 'cannot be nil' },
|
|
30
|
+
# { :source => { :pointer => '/data/attributes/name' }, :detail => 'must be longer' },
|
|
31
|
+
# { :source => { :pointer => '/data/attributes/id' }, :detail => 'must be a uuid' }
|
|
32
|
+
# ]
|
|
33
|
+
# }.to_json
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Direct error document generation
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
options = nil
|
|
40
|
+
resource = ModelWithErrors.new
|
|
41
|
+
resource.errors.add(:name, 'must be awesome')
|
|
42
|
+
|
|
43
|
+
serializable_resource = ActiveModelSerializers::SerializableResource.new(
|
|
44
|
+
resource, {
|
|
45
|
+
serializer: ActiveModel::Serializer::ErrorSerializer,
|
|
46
|
+
adapter: :json_api
|
|
47
|
+
})
|
|
48
|
+
serializable_resource.as_json(options)
|
|
49
|
+
# #=>
|
|
50
|
+
# {
|
|
51
|
+
# :errors =>
|
|
52
|
+
# [
|
|
53
|
+
# { :source => { :pointer => '/data/attributes/name' }, :detail => 'must be awesome' }
|
|
54
|
+
# ]
|
|
55
|
+
# }
|
|
56
|
+
```
|