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.
Files changed (232) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +29 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +15 -0
  4. data/.gitignore +17 -0
  5. data/.rubocop.yml +104 -0
  6. data/.rubocop_todo.yml +167 -0
  7. data/.simplecov +110 -0
  8. data/.travis.yml +39 -24
  9. data/CHANGELOG.md +465 -6
  10. data/CONTRIBUTING.md +105 -0
  11. data/Gemfile +50 -1
  12. data/{MIT-LICENSE.txt → MIT-LICENSE} +3 -2
  13. data/README.md +102 -590
  14. data/Rakefile +93 -8
  15. data/active_model_serializers.gemspec +65 -23
  16. data/appveyor.yml +24 -0
  17. data/bin/bench +171 -0
  18. data/bin/bench_regression +316 -0
  19. data/bin/serve_benchmark +39 -0
  20. data/docs/ARCHITECTURE.md +126 -0
  21. data/docs/README.md +40 -0
  22. data/docs/STYLE.md +58 -0
  23. data/docs/general/adapters.md +245 -0
  24. data/docs/general/caching.md +52 -0
  25. data/docs/general/configuration_options.md +100 -0
  26. data/docs/general/deserialization.md +100 -0
  27. data/docs/general/getting_started.md +133 -0
  28. data/docs/general/instrumentation.md +40 -0
  29. data/docs/general/key_transforms.md +40 -0
  30. data/docs/general/logging.md +14 -0
  31. data/docs/general/rendering.md +255 -0
  32. data/docs/general/serializers.md +372 -0
  33. data/docs/how-open-source-maintained.jpg +0 -0
  34. data/docs/howto/add_pagination_links.md +139 -0
  35. data/docs/howto/add_root_key.md +51 -0
  36. data/docs/howto/outside_controller_use.md +58 -0
  37. data/docs/howto/passing_arbitrary_options.md +27 -0
  38. data/docs/howto/serialize_poro.md +32 -0
  39. data/docs/howto/test.md +152 -0
  40. data/docs/integrations/ember-and-json-api.md +112 -0
  41. data/docs/integrations/grape.md +19 -0
  42. data/docs/jsonapi/errors.md +56 -0
  43. data/docs/jsonapi/schema/schema.json +366 -0
  44. data/docs/jsonapi/schema.md +151 -0
  45. data/docs/rfcs/0000-namespace.md +106 -0
  46. data/docs/rfcs/template.md +15 -0
  47. data/lib/action_controller/serialization.rb +31 -36
  48. data/lib/active_model/serializable_resource.rb +11 -0
  49. data/lib/active_model/serializer/adapter/attributes.rb +15 -0
  50. data/lib/active_model/serializer/adapter/base.rb +16 -0
  51. data/lib/active_model/serializer/adapter/json.rb +15 -0
  52. data/lib/active_model/serializer/adapter/json_api.rb +15 -0
  53. data/lib/active_model/serializer/adapter/null.rb +15 -0
  54. data/lib/active_model/serializer/adapter.rb +24 -0
  55. data/lib/active_model/serializer/array_serializer.rb +9 -0
  56. data/lib/active_model/serializer/association.rb +19 -0
  57. data/lib/active_model/serializer/associations.rb +87 -220
  58. data/lib/active_model/serializer/attribute.rb +25 -0
  59. data/lib/active_model/serializer/attributes.rb +82 -0
  60. data/lib/active_model/serializer/belongs_to_reflection.rb +10 -0
  61. data/lib/active_model/serializer/caching.rb +333 -0
  62. data/lib/active_model/serializer/collection_reflection.rb +7 -0
  63. data/lib/active_model/serializer/collection_serializer.rb +64 -0
  64. data/lib/active_model/serializer/configuration.rb +35 -0
  65. data/lib/active_model/serializer/error_serializer.rb +10 -0
  66. data/lib/active_model/serializer/errors_serializer.rb +27 -0
  67. data/lib/active_model/serializer/field.rb +90 -0
  68. data/lib/active_model/serializer/fieldset.rb +31 -0
  69. data/lib/active_model/serializer/has_many_reflection.rb +10 -0
  70. data/lib/active_model/serializer/has_one_reflection.rb +10 -0
  71. data/lib/active_model/serializer/include_tree.rb +111 -0
  72. data/lib/active_model/serializer/links.rb +35 -0
  73. data/lib/active_model/serializer/lint.rb +146 -0
  74. data/lib/active_model/serializer/meta.rb +29 -0
  75. data/lib/active_model/serializer/null.rb +17 -0
  76. data/lib/active_model/serializer/reflection.rb +147 -0
  77. data/lib/active_model/serializer/singular_reflection.rb +7 -0
  78. data/lib/active_model/serializer/type.rb +25 -0
  79. data/lib/active_model/{serializers → serializer}/version.rb +1 -1
  80. data/lib/active_model/serializer.rb +158 -481
  81. data/lib/active_model_serializers/adapter/attributes.rb +76 -0
  82. data/lib/active_model_serializers/adapter/base.rb +83 -0
  83. data/lib/active_model_serializers/adapter/json.rb +21 -0
  84. data/lib/active_model_serializers/adapter/json_api/deserialization.rb +213 -0
  85. data/lib/active_model_serializers/adapter/json_api/error.rb +96 -0
  86. data/lib/active_model_serializers/adapter/json_api/jsonapi.rb +49 -0
  87. data/lib/active_model_serializers/adapter/json_api/link.rb +83 -0
  88. data/lib/active_model_serializers/adapter/json_api/meta.rb +37 -0
  89. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +62 -0
  90. data/lib/active_model_serializers/adapter/json_api/relationship.rb +52 -0
  91. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +37 -0
  92. data/lib/active_model_serializers/adapter/json_api.rb +516 -0
  93. data/lib/active_model_serializers/adapter/null.rb +9 -0
  94. data/lib/active_model_serializers/adapter.rb +92 -0
  95. data/lib/active_model_serializers/callbacks.rb +55 -0
  96. data/lib/active_model_serializers/deprecate.rb +55 -0
  97. data/lib/active_model_serializers/deserialization.rb +13 -0
  98. data/lib/active_model_serializers/json_pointer.rb +14 -0
  99. data/lib/active_model_serializers/key_transform.rb +70 -0
  100. data/lib/active_model_serializers/logging.rb +122 -0
  101. data/lib/active_model_serializers/model.rb +49 -0
  102. data/lib/active_model_serializers/railtie.rb +46 -0
  103. data/lib/active_model_serializers/register_jsonapi_renderer.rb +65 -0
  104. data/lib/active_model_serializers/serializable_resource.rb +81 -0
  105. data/lib/active_model_serializers/serialization_context.rb +32 -0
  106. data/lib/active_model_serializers/test/schema.rb +138 -0
  107. data/lib/active_model_serializers/test/serializer.rb +125 -0
  108. data/lib/active_model_serializers/test.rb +7 -0
  109. data/lib/active_model_serializers.rb +32 -89
  110. data/lib/generators/rails/USAGE +6 -0
  111. data/lib/generators/rails/resource_override.rb +10 -0
  112. data/lib/generators/rails/serializer_generator.rb +36 -0
  113. data/lib/generators/rails/templates/serializer.rb.erb +8 -0
  114. data/lib/grape/active_model_serializers.rb +14 -0
  115. data/lib/grape/formatters/active_model_serializers.rb +15 -0
  116. data/lib/grape/helpers/active_model_serializers.rb +16 -0
  117. data/test/action_controller/adapter_selector_test.rb +53 -0
  118. data/test/action_controller/explicit_serializer_test.rb +134 -0
  119. data/test/action_controller/json/include_test.rb +167 -0
  120. data/test/action_controller/json_api/deserialization_test.rb +112 -0
  121. data/test/action_controller/json_api/errors_test.rb +41 -0
  122. data/test/action_controller/json_api/linked_test.rb +197 -0
  123. data/test/action_controller/json_api/pagination_test.rb +116 -0
  124. data/test/action_controller/json_api/transform_test.rb +181 -0
  125. data/test/action_controller/serialization_scope_name_test.rb +229 -0
  126. data/test/action_controller/serialization_test.rb +469 -0
  127. data/test/active_model_serializers/adapter_for_test.rb +208 -0
  128. data/test/active_model_serializers/json_pointer_test.rb +20 -0
  129. data/test/active_model_serializers/key_transform_test.rb +263 -0
  130. data/test/active_model_serializers/logging_test.rb +77 -0
  131. data/test/active_model_serializers/model_test.rb +9 -0
  132. data/test/active_model_serializers/railtie_test_isolated.rb +63 -0
  133. data/test/active_model_serializers/serialization_context_test_isolated.rb +58 -0
  134. data/test/active_model_serializers/test/schema_test.rb +130 -0
  135. data/test/active_model_serializers/test/serializer_test.rb +62 -0
  136. data/test/active_record_test.rb +9 -0
  137. data/test/adapter/deprecation_test.rb +100 -0
  138. data/test/adapter/json/belongs_to_test.rb +45 -0
  139. data/test/adapter/json/collection_test.rb +90 -0
  140. data/test/adapter/json/has_many_test.rb +45 -0
  141. data/test/adapter/json/transform_test.rb +93 -0
  142. data/test/adapter/json_api/belongs_to_test.rb +155 -0
  143. data/test/adapter/json_api/collection_test.rb +95 -0
  144. data/test/adapter/json_api/errors_test.rb +78 -0
  145. data/test/adapter/json_api/fields_test.rb +87 -0
  146. data/test/adapter/json_api/has_many_embed_ids_test.rb +43 -0
  147. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +96 -0
  148. data/test/adapter/json_api/has_many_test.rb +144 -0
  149. data/test/adapter/json_api/has_one_test.rb +80 -0
  150. data/test/adapter/json_api/json_api_test.rb +35 -0
  151. data/test/adapter/json_api/linked_test.rb +392 -0
  152. data/test/adapter/json_api/links_test.rb +93 -0
  153. data/test/adapter/json_api/pagination_links_test.rb +166 -0
  154. data/test/adapter/json_api/parse_test.rb +137 -0
  155. data/test/adapter/json_api/relationship_test.rb +161 -0
  156. data/test/adapter/json_api/relationships_test.rb +199 -0
  157. data/test/adapter/json_api/resource_identifier_test.rb +85 -0
  158. data/test/adapter/json_api/resource_meta_test.rb +100 -0
  159. data/test/adapter/json_api/toplevel_jsonapi_test.rb +82 -0
  160. data/test/adapter/json_api/transform_test.rb +502 -0
  161. data/test/adapter/json_api/type_test.rb +61 -0
  162. data/test/adapter/json_test.rb +45 -0
  163. data/test/adapter/null_test.rb +23 -0
  164. data/test/adapter/polymorphic_test.rb +171 -0
  165. data/test/adapter_test.rb +67 -0
  166. data/test/array_serializer_test.rb +20 -73
  167. data/test/benchmark/app.rb +65 -0
  168. data/test/benchmark/benchmarking_support.rb +67 -0
  169. data/test/benchmark/bm_caching.rb +119 -0
  170. data/test/benchmark/bm_transform.rb +34 -0
  171. data/test/benchmark/config.ru +3 -0
  172. data/test/benchmark/controllers.rb +84 -0
  173. data/test/benchmark/fixtures.rb +219 -0
  174. data/test/cache_test.rb +485 -0
  175. data/test/collection_serializer_test.rb +110 -0
  176. data/test/fixtures/active_record.rb +78 -0
  177. data/test/fixtures/poro.rb +282 -0
  178. data/test/generators/scaffold_controller_generator_test.rb +24 -0
  179. data/test/generators/serializer_generator_test.rb +57 -0
  180. data/test/grape_test.rb +82 -0
  181. data/test/include_tree/from_include_args_test.rb +26 -0
  182. data/test/include_tree/from_string_test.rb +94 -0
  183. data/test/include_tree/include_args_to_hash_test.rb +64 -0
  184. data/test/lint_test.rb +49 -0
  185. data/test/logger_test.rb +18 -0
  186. data/test/poro_test.rb +9 -0
  187. data/test/serializable_resource_test.rb +83 -0
  188. data/test/serializers/association_macros_test.rb +36 -0
  189. data/test/serializers/associations_test.rb +295 -0
  190. data/test/serializers/attribute_test.rb +151 -0
  191. data/test/serializers/attributes_test.rb +52 -0
  192. data/test/serializers/caching_configuration_test_isolated.rb +170 -0
  193. data/test/serializers/configuration_test.rb +32 -0
  194. data/test/serializers/fieldset_test.rb +14 -0
  195. data/test/serializers/meta_test.rb +196 -0
  196. data/test/serializers/options_test.rb +21 -0
  197. data/test/serializers/read_attribute_for_serialization_test.rb +79 -0
  198. data/test/serializers/root_test.rb +21 -0
  199. data/test/serializers/serialization_test.rb +55 -0
  200. data/test/serializers/serializer_for_test.rb +134 -0
  201. data/test/support/custom_schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
  202. data/test/support/isolated_unit.rb +79 -0
  203. data/test/support/rails5_shims.rb +47 -0
  204. data/test/support/rails_app.rb +45 -0
  205. data/test/support/schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
  206. data/test/support/schemas/active_model_serializers/test/schema_test/my/show.json +6 -0
  207. data/test/support/schemas/custom/show.json +7 -0
  208. data/test/support/schemas/hyper_schema.json +93 -0
  209. data/test/support/schemas/render_using_json_api.json +43 -0
  210. data/test/support/schemas/simple_json_pointers.json +10 -0
  211. data/test/support/serialization_testing.rb +53 -0
  212. data/test/test_helper.rb +48 -23
  213. metadata +449 -43
  214. data/DESIGN.textile +0 -586
  215. data/Gemfile.edge +0 -9
  216. data/bench/perf.rb +0 -43
  217. data/cruft.md +0 -19
  218. data/lib/active_model/array_serializer.rb +0 -104
  219. data/lib/active_record/serializer_override.rb +0 -16
  220. data/lib/generators/resource_override.rb +0 -13
  221. data/lib/generators/serializer/USAGE +0 -9
  222. data/lib/generators/serializer/serializer_generator.rb +0 -42
  223. data/lib/generators/serializer/templates/serializer.rb +0 -19
  224. data/test/association_test.rb +0 -592
  225. data/test/caching_test.rb +0 -96
  226. data/test/generators_test.rb +0 -85
  227. data/test/no_serialization_scope_test.rb +0 -34
  228. data/test/serialization_scope_name_test.rb +0 -67
  229. data/test/serialization_test.rb +0 -392
  230. data/test/serializer_support_test.rb +0 -51
  231. data/test/serializer_test.rb +0 -1465
  232. data/test/test_fakes.rb +0 -217
@@ -0,0 +1,14 @@
1
+ [Back to Guides](../README.md)
2
+
3
+ # Logging
4
+
5
+ The default logger in a Rails application will be `Rails.logger`.
6
+
7
+ When there is no `Rails.logger`, the default logger is an instance of
8
+ `ActiveSupport::TaggedLogging` logging to STDOUT.
9
+
10
+ You may customize the logger in an initializer, for example:
11
+
12
+ ```ruby
13
+ ActiveModelSerializers.logger = Logger.new(STDOUT)
14
+ ```
@@ -0,0 +1,255 @@
1
+ [Back to Guides](../README.md)
2
+
3
+ # Rendering
4
+
5
+ ### Implicit Serializer
6
+
7
+ In your controllers, when you use `render :json`, Rails will now first search
8
+ for a serializer for the object and use it if available.
9
+
10
+ ```ruby
11
+ class PostsController < ApplicationController
12
+ def show
13
+ @post = Post.find(params[:id])
14
+
15
+ render json: @post
16
+ end
17
+ end
18
+ ```
19
+
20
+ In this case, Rails will look for a serializer named `PostSerializer`, and if
21
+ it exists, use it to serialize the `Post`.
22
+
23
+ ### Explicit Serializer
24
+
25
+ If you wish to use a serializer other than the default, you can explicitly pass it to the renderer.
26
+
27
+ #### 1. For a resource:
28
+
29
+ ```ruby
30
+ render json: @post, serializer: PostPreviewSerializer
31
+ ```
32
+
33
+ #### 2. For a resource collection:
34
+
35
+ Specify the serializer for each resource with `each_serializer`
36
+
37
+ ```ruby
38
+ render json: @posts, each_serializer: PostPreviewSerializer
39
+ ```
40
+
41
+ The default serializer for collections is `CollectionSerializer`.
42
+
43
+ Specify the collection serializer with the `serializer` option.
44
+
45
+ ```ruby
46
+ render json: @posts, serializer: CollectionSerializer, each_serializer: PostPreviewSerializer
47
+ ```
48
+
49
+ ## Serializing non-ActiveRecord objects
50
+
51
+ All serializable resources must pass the
52
+ [ActiveModel::Serializer::Lint::Tests](../../lib/active_model/serializer/lint.rb#L17).
53
+
54
+ See the ActiveModelSerializers::Model for a base class that implements the full
55
+ API for a plain-old Ruby object (PORO).
56
+
57
+ ## SerializableResource options
58
+
59
+ The `options` hash passed to `render` or `ActiveModelSerializers::SerializableResource.new(resource, options)`
60
+ are partitioned into `serializer_opts` and `adapter_opts`. `adapter_opts` are passed to new Adapters;
61
+ `serializer_opts` are passed to new Serializers.
62
+
63
+ The `adapter_opts` are specified in [ActiveModelSerializers::SerializableResource::ADAPTER_OPTIONS](../../lib/active_model_serializers/serializable_resource.rb#L5).
64
+ The `serializer_opts` are the remaining options.
65
+
66
+ (In Rails, the `options` are also passed to the `as_json(options)` or `to_json(options)`
67
+ methods on the resource serialization by the Rails JSON renderer. They are, therefore, important
68
+ to know about, but not part of ActiveModelSerializers.)
69
+
70
+ See [ARCHITECTURE](../ARCHITECTURE.md) for more information.
71
+
72
+ ### adapter_opts
73
+
74
+ #### fields
75
+
76
+ PR please :)
77
+
78
+ #### adapter
79
+
80
+ PR please :)
81
+
82
+ #### key_transform
83
+
84
+ ```render json: posts, each_serializer: PostSerializer, key_transform: :camel_lower```
85
+
86
+ See [Key Transforms](key_transforms.md) for more informaiton.
87
+
88
+ #### meta
89
+
90
+ A `meta` member can be used to include non-standard meta-information. `meta` can
91
+ be utilized in several levels in a response.
92
+
93
+ ##### Top-level
94
+
95
+ To set top-level `meta` in a response, specify it in the `render` call.
96
+
97
+ ```ruby
98
+ render json: @post, meta: { total: 10 }
99
+ ```
100
+
101
+ The key can be customized using `meta_key` option.
102
+
103
+ ```ruby
104
+ render json: @post, meta: { total: 10 }, meta_key: "custom_meta"
105
+ ```
106
+
107
+ `meta` will only be included in your response if you are using an Adapter that
108
+ supports `root`, e.g., `JsonApi` and `Json` adapters. The default adapter,
109
+ `Attributes` does not have `root`.
110
+
111
+
112
+ ##### Resource-level
113
+
114
+ To set resource-level `meta` in a response, define meta in a serializer with one
115
+ of the following methods:
116
+
117
+ As a single, static string.
118
+
119
+ ```ruby
120
+ meta stuff: 'value'
121
+ ```
122
+
123
+ As a block containing a Hash.
124
+
125
+ ```ruby
126
+ meta do
127
+ {
128
+ rating: 4,
129
+ comments_count: object.comments.count
130
+ }
131
+ end
132
+ ```
133
+
134
+
135
+ #### links
136
+
137
+ If you wish to use Rails url helpers for link generation, e.g., `link(:resources) { resources_url }`, ensure your application sets
138
+ `Rails.application.routes.default_url_options`.
139
+
140
+ ##### Top-level
141
+
142
+ JsonApi supports a [links object](http://jsonapi.org/format/#document-links) to be specified at top-level, that you can specify in the `render`:
143
+
144
+ ```ruby
145
+ links_object = {
146
+ href: "http://example.com/api/posts",
147
+ meta: {
148
+ count: 10
149
+ }
150
+ }
151
+ render json: @posts, links: links_object
152
+ ```
153
+
154
+ That's the result:
155
+
156
+ ```json
157
+ {
158
+ "data": [
159
+ {
160
+ "type": "posts",
161
+ "id": "1",
162
+ "attributes": {
163
+ "title": "JSON API is awesome!",
164
+ "body": "You should be using JSON API",
165
+ "created": "2015-05-22T14:56:29.000Z",
166
+ "updated": "2015-05-22T14:56:28.000Z"
167
+ }
168
+ }
169
+ ],
170
+ "links": {
171
+ "href": "http://example.com/api/posts",
172
+ "meta": {
173
+ "count": 10
174
+ }
175
+ }
176
+ }
177
+ ```
178
+
179
+ This feature is specific to JsonApi, so you have to use the use the [JsonApi Adapter](adapters.md#jsonapi)
180
+
181
+
182
+ ##### Resource-level
183
+
184
+ In your serializer, define each link in one of the following methods:
185
+
186
+ As a static string
187
+
188
+ ```ruby
189
+ link :link_name, 'https://example.com/resource'
190
+ ```
191
+
192
+ As a block to be evaluated. When using Rails, URL helpers are available.
193
+ Ensure your application sets `Rails.application.routes.default_url_options`.
194
+
195
+ ```ruby
196
+ link :link_name_ do
197
+ "https://example.com/resource/#{object.id}"
198
+ end
199
+
200
+ link(:link_name) { "https://example.com/resource/#{object.id}" }
201
+
202
+ link(:link_name) { resource_url(object) }
203
+
204
+ link(:link_name) { url_for(controller: 'controller_name', action: 'index', only_path: false) }
205
+
206
+ ```
207
+
208
+ ### serializer_opts
209
+
210
+ #### include
211
+
212
+ PR please :)
213
+
214
+ #### Overriding the root key
215
+
216
+ Overriding the resource root only applies when using the JSON adapter.
217
+
218
+ Normally, the resource root is derived from the class name of the resource being serialized.
219
+ e.g. `UserPostSerializer.new(UserPost.new)` will be serialized with the root `user_post` or `user_posts` according the adapter collection pluralization rules.
220
+
221
+ 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:
222
+
223
+ ```ruby
224
+ render json: @user_post, root: "admin_post", adapter: :json
225
+ ```
226
+
227
+ This will be rendered as:
228
+ ```json
229
+ {
230
+ "admin_post": {
231
+ "title": "how to do open source"
232
+ }
233
+ }
234
+ ```
235
+ 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.
236
+
237
+ #### serializer
238
+
239
+ PR please :)
240
+
241
+ #### scope
242
+
243
+ PR please :)
244
+
245
+ #### scope_name
246
+
247
+ PR please :)
248
+
249
+ ## Using a serializer without `render`
250
+
251
+ See [Usage outside of a controller](../howto/outside_controller_use.md#serializing-before-controller-render).
252
+
253
+ ## Pagination
254
+
255
+ See [How to add pagination links](https://github.com/rails-api/active_model_serializers/blob/master/docs/howto/add_pagination_links.md).
@@ -0,0 +1,372 @@
1
+ [Back to Guides](../README.md)
2
+
3
+ # Serializers
4
+
5
+ Given a serializer class:
6
+
7
+ ```ruby
8
+ class SomeSerializer < ActiveModel::Serializer
9
+ end
10
+ ```
11
+
12
+ The following methods may be defined in it:
13
+
14
+ ### Attributes
15
+
16
+ #### ::attributes
17
+
18
+ Serialization of the resource `title` and `body`
19
+
20
+ | In Serializer | #attributes |
21
+ |---------------------------- |-------------|
22
+ | `attributes :title, :body` | `{ title: 'Some Title', body: 'Some Body' }`
23
+ | `attributes :title, :body`<br>`def body "Special #{object.body}" end` | `{ title: 'Some Title', body: 'Special Some Body' }`
24
+
25
+
26
+ #### ::attribute
27
+
28
+ Serialization of the resource `title`
29
+
30
+ | In Serializer | #attributes |
31
+ |---------------------------- |-------------|
32
+ | `attribute :title` | `{ title: 'Some Title' } `
33
+ | `attribute :title, key: :name` | `{ name: 'Some Title' } `
34
+ | `attribute :title { 'A Different Title'}` | `{ title: 'A Different Title' } `
35
+ | `attribute :title`<br>`def title 'A Different Title' end` | `{ title: 'A Different Title' }`
36
+
37
+ [PR please for conditional attributes:)](https://github.com/rails-api/active_model_serializers/pull/1403)
38
+
39
+ ### Associations
40
+
41
+ The interface for associations is, generically:
42
+
43
+ > `association_type(association_name, options, &block)`
44
+
45
+ Where:
46
+
47
+ - `association_type` may be `has_one`, `has_many`, `belongs_to`.
48
+ - `association_name` is a method name the serializer calls.
49
+ - optional: `options` may be:
50
+ - `key:` The name used for the serialized association.
51
+ - `serializer:`
52
+ - `if:`
53
+ - `unless:`
54
+ - `virtual_value:`
55
+ - `polymorphic:` defines if polymorphic relation type should be nested in serialized association.
56
+ - optional: `&block` is a context that returns the association's attributes.
57
+ - prevents `association_name` method from being called.
58
+ - return value of block is used as the association value.
59
+ - yields the `serializer` to the block.
60
+ - `include_data false` prevents the `data` key from being rendered in the JSON API relationship.
61
+
62
+ #### ::has_one
63
+
64
+ e.g.
65
+
66
+ ```ruby
67
+ has_one :bio
68
+ has_one :blog, key: :site
69
+ has_one :maker, virtual_value: { id: 1 }
70
+
71
+ has_one :blog do |serializer|
72
+ serializer.cached_blog
73
+ end
74
+
75
+ def cached_blog
76
+ cache_store.fetch("cached_blog:#{object.updated_at}") do
77
+ Blog.find(object.blog_id)
78
+ end
79
+ end
80
+ ```
81
+
82
+ ```ruby
83
+ has_one :blog, if: :show_blog?
84
+ # you can also use a string or lambda
85
+ # has_one :blog, if: 'scope.admin?'
86
+ # has_one :blog, if: -> (serializer) { serializer.scope.admin? }
87
+ # has_one :blog, if: -> { scope.admin? }
88
+
89
+ def show_blog?
90
+ scope.admin?
91
+ end
92
+ ```
93
+
94
+ #### ::has_many
95
+
96
+ e.g.
97
+
98
+ ```ruby
99
+ has_many :comments
100
+ has_many :comments, key: :reviews
101
+ has_many :comments, serializer: CommentPreviewSerializer
102
+ has_many :reviews, virtual_value: [{ id: 1 }, { id: 2 }]
103
+ has_many :comments, key: :last_comments do
104
+ last(1)
105
+ end
106
+ ```
107
+
108
+ #### ::belongs_to
109
+
110
+ e.g.
111
+
112
+ ```ruby
113
+ belongs_to :author, serializer: AuthorPreviewSerializer
114
+ belongs_to :author, key: :writer
115
+ belongs_to :post
116
+ belongs_to :blog
117
+ def blog
118
+ Blog.new(id: 999, name: 'Custom blog')
119
+ end
120
+ ```
121
+
122
+ ### Polymorphic Relationships
123
+
124
+ Polymorphic relationships are serialized by specifying the relationship, like any other association. For example:
125
+
126
+ ```ruby
127
+ class PictureSerializer < ActiveModel::Serializer
128
+ has_one :imageable
129
+ end
130
+ ```
131
+
132
+ For more context, see the [tests](../../test/adapter/polymorphic_test.rb) for each adapter.
133
+
134
+ ### Caching
135
+
136
+ #### ::cache
137
+
138
+ e.g.
139
+
140
+ ```ruby
141
+ cache key: 'post', expires_in: 0.1, skip_digest: true
142
+ cache expires_in: 1.day, skip_digest: true
143
+ cache key: 'writer', skip_digest: true
144
+ cache only: [:name], skip_digest: true
145
+ cache except: [:content], skip_digest: true
146
+ cache key: 'blog'
147
+ cache only: [:id]
148
+ ```
149
+
150
+ #### #cache_key
151
+
152
+ e.g.
153
+
154
+ ```ruby
155
+ # Uses a custom non-time-based cache key
156
+ def cache_key
157
+ "#{self.class.name.downcase}/#{self.id}"
158
+ end
159
+ ```
160
+
161
+ ### Other
162
+
163
+ #### ::type
164
+
165
+ The `::type` method defines the JSONAPI [type](http://jsonapi.org/format/#document-resource-object-identification) that will be rendered for this serializer.
166
+ It either takes a `String` or `Symbol` as parameter.
167
+
168
+ Note: This method is useful only when using the `:json_api` adapter.
169
+
170
+ Examples:
171
+ ```ruby
172
+ class UserProfileSerializer < ActiveModel::Serializer
173
+ type 'profile'
174
+ end
175
+ class AuthorProfileSerializer < ActiveModel::Serializer
176
+ type :profile
177
+ end
178
+ ```
179
+
180
+ With the `:json_api` adapter, the previous serializers would be rendered as:
181
+
182
+ ``` json
183
+ {
184
+ "data": {
185
+ "id": "1",
186
+ "type": "profile"
187
+ }
188
+ }
189
+ ```
190
+
191
+ #### ::link
192
+
193
+ ```ruby
194
+ link :self do
195
+ href "https://example.com/link_author/#{object.id}"
196
+ end
197
+ link :author { link_author_url(object) }
198
+ link :link_authors { link_authors_url }
199
+ link :other, 'https://example.com/resource'
200
+ link :posts { link_author_posts_url(object) }
201
+ ```
202
+
203
+ #### #object
204
+
205
+ The object being serialized.
206
+
207
+ #### #root
208
+
209
+ PR please :)
210
+
211
+ #### #scope
212
+
213
+ Allows you to include in the serializer access to an external method.
214
+
215
+ It's intended to provide an authorization context to the serializer, so that
216
+ you may e.g. show an admin all comments on a post, else only published comments.
217
+
218
+ - `scope` is a method on the serializer instance that comes from `options[:scope]`. It may be nil.
219
+ - `scope_name` is an option passed to the new serializer (`options[:scope_name]`). The serializer
220
+ defines a method with that name that calls the `scope`, e.g. `def current_user; scope; end`.
221
+ Note: it does not define the method if the serializer instance responds to it.
222
+
223
+ That's a lot of words, so here's some examples:
224
+
225
+ First, let's assume the serializer is instantiated in the controller, since that's the usual scenario.
226
+ We'll refer to the serialization context as `controller`.
227
+
228
+ | options | `Serializer#scope` | method definition |
229
+ |-------- | ------------------|--------------------|
230
+ | `scope: current_user, scope_name: :current_user` | `current_user` | `Serializer#current_user` calls `controller.current_user`
231
+ | `scope: view_context, scope_name: :view_context` | `view_context` | `Serializer#view_context` calls `controller.view_context`
232
+
233
+ We can take advantage of the scope to customize the objects returned based
234
+ on the current user (scope).
235
+
236
+ For example, we can limit the posts the current user sees to those they created:
237
+
238
+ ```ruby
239
+ class PostSerializer < ActiveModel::Serializer
240
+ attributes :id, :title, :body
241
+
242
+ # scope comments to those created_by the current user
243
+ has_many :comments do
244
+ object.comments.where(created_by: current_user)
245
+ end
246
+ end
247
+ ```
248
+
249
+ Whether you write the method as above or as `object.comments.where(created_by: scope)`
250
+ is a matter of preference (assuming `scope_name` has been set).
251
+
252
+ ##### Controller Authorization Context
253
+
254
+ In the controller, the scope/scope_name options are equal to
255
+ the [`serialization_scope`method](https://github.com/rails-api/active_model_serializers/blob/d02cd30fe55a3ea85e1d351b6e039620903c1871/lib/action_controller/serialization.rb#L13-L20),
256
+ which is `:current_user`, by default.
257
+
258
+ Specfically, the `scope_name` is defaulted to `:current_user`, and may be set as
259
+ `serialization_scope :view_context`. The `scope` is set to `send(scope_name)` when `scope_name` is
260
+ present and the controller responds to `scope_name`.
261
+
262
+ Thus, in a serializer, the controller provides `current_user` as the
263
+ current authorization scope when you call `render :json`.
264
+
265
+ **IMPORTANT**: Since the scope is set at render, you may want to customize it so that `current_user` isn't
266
+ called on every request. This was [also a problem](https://github.com/rails-api/active_model_serializers/pull/1252#issuecomment-159810477)
267
+ in [`0.9`](https://github.com/rails-api/active_model_serializers/tree/0-9-stable#customizing-scope).
268
+
269
+ We can change the scope from `current_user` to `view_context`.
270
+
271
+ ```diff
272
+ class SomeController < ActionController::Base
273
+ + serialization_scope :view_context
274
+
275
+ def current_user
276
+ User.new(id: 2, name: 'Bob', admin: true)
277
+ end
278
+
279
+ def edit
280
+ user = User.new(id: 1, name: 'Pete')
281
+ render json: user, serializer: AdminUserSerializer, adapter: :json_api
282
+ end
283
+ end
284
+ ```
285
+
286
+ We could then use the controller method `view_context` in our serializer, like so:
287
+
288
+ ```diff
289
+ class AdminUserSerializer < ActiveModel::Serializer
290
+ attributes :id, :name, :can_edit
291
+
292
+ def can_edit?
293
+ + view_context.current_user.admin?
294
+ end
295
+ end
296
+ ```
297
+
298
+ So that when we render the `#edit` action, we'll get
299
+
300
+ ```json
301
+ {"data":{"id":"1","type":"users","attributes":{"name":"Pete","can_edit":true}}}
302
+ ```
303
+
304
+ Where `can_edit` is `view_context.current_user.admin?` (true).
305
+
306
+ #### #read_attribute_for_serialization(key)
307
+
308
+ The serialized value for a given key. e.g. `read_attribute_for_serialization(:title) #=> 'Hello World'`
309
+
310
+ #### #links
311
+
312
+ PR please :)
313
+
314
+ #### #json_key
315
+
316
+ PR please :)
317
+
318
+ ## Examples
319
+
320
+ Given two models, a `Post(title: string, body: text)` and a
321
+ `Comment(name: string, body: text, post_id: integer)`, you will have two
322
+ serializers:
323
+
324
+ ```ruby
325
+ class PostSerializer < ActiveModel::Serializer
326
+ cache key: 'posts', expires_in: 3.hours
327
+ attributes :title, :body
328
+
329
+ has_many :comments
330
+ end
331
+ ```
332
+
333
+ and
334
+
335
+ ```ruby
336
+ class CommentSerializer < ActiveModel::Serializer
337
+ attributes :name, :body
338
+
339
+ belongs_to :post
340
+ end
341
+ ```
342
+
343
+ Generally speaking, you, as a user of ActiveModelSerializers, will write (or generate) these
344
+ serializer classes.
345
+
346
+ ## More Info
347
+
348
+ For more information, see [the Serializer class on GitHub](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model/serializer.rb)
349
+
350
+ ## Overriding association methods
351
+
352
+ To override an association, call `has_many`, `has_one` or `belongs_to` with a block:
353
+
354
+ ```ruby
355
+ class PostSerializer < ActiveModel::Serializer
356
+ has_many :comments do
357
+ object.comments.active
358
+ end
359
+ end
360
+ ```
361
+
362
+ ## Overriding attribute methods
363
+
364
+ To override an attribute, call `attribute` with a block:
365
+
366
+ ```ruby
367
+ class PostSerializer < ActiveModel::Serializer
368
+ attribute :body do
369
+ object.body.downcase
370
+ end
371
+ end
372
+ ```
Binary file