active_model_serializers 0.8.3 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
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
data/README.md CHANGED
@@ -1,655 +1,167 @@
1
- [![Build Status](https://api.travis-ci.org/rails-api/active_model_serializers.png)](https://travis-ci.org/rails-api/active_model_serializers) [![Code Climate](https://codeclimate.com/github/rails-api/active_model_serializers.png)](https://codeclimate.com/github/rails-api/active_model_serializers)
1
+ # ActiveModelSerializers
2
2
 
3
- # Purpose
3
+ <table>
4
+ <tr>
5
+ <td>Build Status</td>
6
+ <td>
7
+ <a href="https://travis-ci.org/rails-api/active_model_serializers"><img src="https://travis-ci.org/rails-api/active_model_serializers.svg?branch=master" alt="Build Status" ></a>
8
+ <a href="https://ci.appveyor.com/project/joaomdmoura/active-model-serializers/branch/master"><img src="https://ci.appveyor.com/api/projects/status/x6xdjydutm54gvyt/branch/master?svg=true" alt="Build status"></a>
9
+ </td>
10
+ </tr>
11
+ <tr>
12
+ <td>Code Quality</td>
13
+ <td>
14
+ <a href="https://codeclimate.com/github/rails-api/active_model_serializers"><img src="https://codeclimate.com/github/rails-api/active_model_serializers/badges/gpa.svg" alt="Code Quality"></a>
15
+ <a href="https://codebeat.co/projects/github-com-rails-api-active_model_serializers"><img src="https://codebeat.co/badges/a9ab35fa-8b5a-4680-9d4e-a81f9a55ebcd" alt="codebeat" ></a>
16
+ <a href="https://codeclimate.com/github/rails-api/active_model_serializers/coverage"><img src="https://codeclimate.com/github/rails-api/active_model_serializers/badges/coverage.svg" alt="Test Coverage"></a>
17
+ </td>
18
+ </tr>
19
+ <tr>
20
+ <td>Issue Stats</td>
21
+ <td>
22
+ <a href="https://github.com/rails-api/active_model_serializers/pulse/monthly">Pulse</a>
23
+ </td>
24
+ </tr>
25
+ </table>
4
26
 
5
- The purpose of `ActiveModel::Serializers` is to provide an object to
6
- encapsulate serialization of `ActiveModel` objects, including `ActiveRecord`
7
- objects.
8
27
 
9
- Serializers know about both a model and the `current_user`, so you can
10
- customize serialization based upon whether a user is authorized to see the
11
- content.
28
+ ## Documentation
12
29
 
13
- In short, **serializers replace hash-driven development with object-oriented
14
- development.**
30
+ - [0.10 (master) Documentation](https://github.com/rails-api/active_model_serializers/tree/master)
31
+ - [![API Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/github/rails-api/active_model_serializers/v0.10.0)
32
+ - [Guides](docs)
33
+ - [0.9 (0-9-stable) Documentation](https://github.com/rails-api/active_model_serializers/tree/0-9-stable)
34
+ - [![API Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/github/rails-api/active_model_serializers/0-9-stable)
35
+ - [0.8 (0-8-stable) Documentation](https://github.com/rails-api/active_model_serializers/tree/0-8-stable)
36
+ - [![API Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/github/rails-api/active_model_serializers/0-8-stable)
15
37
 
16
- # Installing Serializers
38
+ ## About
17
39
 
18
- The easiest way to install `ActiveModel::Serializers` is to add it to your
19
- `Gemfile`:
40
+ ActiveModelSerializers brings convention over configuration to your JSON generation.
20
41
 
21
- ```ruby
22
- gem "active_model_serializers", "~> 0.8.0"
23
- ```
24
-
25
- Then, install it on the command line:
26
-
27
- ```
28
- $ bundle install
29
- ```
30
-
31
- # Creating a Serializer
32
-
33
- The easiest way to create a new serializer is to generate a new resource, which
34
- will generate a serializer at the same time:
35
-
36
- ```
37
- $ rails g resource post title:string body:string
38
- ```
39
-
40
- This will generate a serializer in `app/serializers/post_serializer.rb` for
41
- your new model. You can also generate a serializer for an existing model with
42
- the serializer generator:
43
-
44
- ```
45
- $ rails g serializer post
46
- ```
47
-
48
- ### Support for PORO's and other ORM's.
49
-
50
- Currently `ActiveModel::Serializers` adds serialization support to all models
51
- that descend from `ActiveRecord` or include `Mongoid::Document`. If you are
52
- using another ORM, or if you are using objects that are `ActiveModel`
53
- compliant but do not descend from `ActiveRecord` or include
54
- `Mongoid::Document`, you must add an include statement for
55
- `ActiveModel::SerializerSupport` to make models serializable. If you
56
- also want to make collections serializable, you should include
57
- `ActiveModel::ArraySerializerSupport` into your ORM's
58
- relation/criteria class.
59
-
60
- # ActiveModel::Serializer
61
-
62
- All new serializers descend from ActiveModel::Serializer
63
-
64
- # render :json
65
-
66
- In your controllers, when you use `render :json`, Rails will now first search
67
- for a serializer for the object and use it if available.
68
-
69
- ```ruby
70
- class PostsController < ApplicationController
71
- def show
72
- @post = Post.find(params[:id])
73
- render :json => @post
74
- end
75
- end
76
- ```
77
-
78
- In this case, Rails will look for a serializer named `PostSerializer`, and if
79
- it exists, use it to serialize the `Post`.
80
-
81
- This also works with `respond_with`, which uses `to_json` under the hood. Also
82
- note that any options passed to `render :json` will be passed to your
83
- serializer and available as `@options` inside.
84
-
85
- To specify a custom serializer for an object, there are 2 options:
86
-
87
- #### 1. Specify the serializer in your model:
88
-
89
- ```ruby
90
- class Post < ActiveRecord::Base
91
- def active_model_serializer
92
- FancyPostSerializer
93
- end
94
- end
95
- ```
96
-
97
- #### 2. Specify the serializer when you render the object:
98
-
99
- ```ruby
100
- render :json => @post, :serializer => FancyPostSerializer
101
- ```
102
-
103
- ## Arrays
104
-
105
- In your controllers, when you use `render :json` for an array of objects, AMS will
106
- use `ActiveModel::ArraySerializer` (included in this project) as the base serializer,
107
- and the individual `Serializer` for the objects contained in that array.
108
-
109
- ```ruby
110
- class PostSerializer < ActiveModel::Serializer
111
- attributes :title, :body
112
- end
113
-
114
- class PostsController < ApplicationController
115
- def index
116
- @posts = Post.all
117
- render :json => @posts
118
- end
119
- end
120
- ```
121
-
122
- Given the example above, the index action will return
123
-
124
- ```json
125
- {
126
- "posts":
127
- [
128
- { "title": "Post 1", "body": "Hello!" },
129
- { "title": "Post 2", "body": "Goodbye!" }
130
- ]
131
- }
132
- ```
133
-
134
- By default, the root element is the name of the controller. For example, `PostsController`
135
- generates a root element "posts". To change it:
136
-
137
- ```ruby
138
- render :json => @posts, :root => "some_posts"
139
- ```
140
-
141
- You may disable the root element for arrays at the top level, which will result in
142
- more concise json. See the next section for ways on how to do this. Disabling the
143
- root element of the array with any of those methods will produce
144
-
145
- ```json
146
- [
147
- { "title": "Post 1", "body": "Hello!" },
148
- { "title": "Post 2", "body": "Goodbye!" }
149
- ]
150
- ```
151
-
152
- To specify a custom serializer for the items within an array:
153
-
154
- ```ruby
155
- render :json => @posts, :each_serializer => FancyPostSerializer
156
- ```
157
-
158
- ## Disabling the root element
159
-
160
- You have 4 options to disable the root element, each with a slightly different scope:
161
-
162
- #### 1. Disable root globally for all, or per class
163
-
164
- In an initializer:
165
-
166
- ```ruby
167
- ActiveSupport.on_load(:active_model_serializers) do
168
- # Disable for all serializers (except ArraySerializer)
169
- ActiveModel::Serializer.root = false
170
-
171
- # Disable for ArraySerializer
172
- ActiveModel::ArraySerializer.root = false
173
- end
174
- ```
175
-
176
- #### 2. Disable root per render call in your controller
177
-
178
- ```ruby
179
- render :json => @posts, :root => false
180
- ```
181
-
182
- #### 3. Subclass the serializer, and specify using it
183
-
184
- ```ruby
185
- class CustomArraySerializer < ActiveModel::ArraySerializer
186
- self.root = false
187
- end
188
-
189
- # controller:
190
- render :json => @posts, :serializer => CustomArraySerializer
191
- ```
192
-
193
- #### 4. Define default_serializer_options in your controller
194
-
195
- If you define `default_serializer_options` method in your controller,
196
- all serializers in actions of this controller and it's children will use them.
197
- One of the options may be `root: false`
198
-
199
- ```ruby
200
- def default_serializer_options
201
- {
202
- root: false
203
- }
204
- end
205
- ```
206
-
207
- ## Getting the old version
208
-
209
- If you find that your project is already relying on the old rails to_json
210
- change `render :json` to `render :json => @your_object.to_json`.
211
-
212
- # Attributes and Associations
213
-
214
- Once you have a serializer, you can specify which attributes and associations
215
- you would like to include in the serialized form.
216
-
217
- ```ruby
218
- class PostSerializer < ActiveModel::Serializer
219
- attributes :id, :title, :body
220
- has_many :comments
221
- end
222
- ```
223
-
224
- ## Attributes
42
+ ActiveModelSerializers works through two components: **serializers** and **adapters**.
225
43
 
226
- For specified attributes, a serializer will look up the attribute on the
227
- object you passed to `render :json`. It uses
228
- `read_attribute_for_serialization`, which `ActiveRecord` objects implement as a
229
- regular attribute lookup.
44
+ Serializers describe _which_ attributes and relationships should be serialized.
230
45
 
231
- Before looking up the attribute on the object, a serializer will check for the
232
- presence of a method with the name of the attribute. This allows serializers to
233
- include properties beyond the simple attributes of the model. For example:
46
+ Adapters describe _how_ attributes and relationships should be serialized.
234
47
 
235
- ```ruby
236
- class PersonSerializer < ActiveModel::Serializer
237
- attributes :first_name, :last_name, :full_name
48
+ SerializableResource co-ordinates the resource, Adapter and Serializer to produce the
49
+ resource serialization. The serialization has the `#as_json`, `#to_json` and `#serializable_hash`
50
+ methods used by the Rails JSON Renderer. (SerializableResource actually delegates
51
+ these methods to the adapter.)
238
52
 
239
- def full_name
240
- "#{object.first_name} #{object.last_name}"
241
- end
242
- end
243
- ```
53
+ By default ActiveModelSerializers will use the **Attributes Adapter**.
54
+ But we strongly advise you to use **JsonApi Adapter**, which
55
+ follows 1.0 of the format specified in [jsonapi.org/format](http://jsonapi.org/format).
56
+ Check how to change the adapter in the sections below.
244
57
 
245
- Within a serializer's methods, you can access the object being
246
- serialized as `object`.
58
+ ## RELEASE CANDIDATE, PLEASE READ
247
59
 
248
- You can also access the `current_user` method, which provides an
249
- authorization context to your serializer. By default, the context
250
- is the current user of your application, but this
251
- [can be customized](#customizing-scope).
60
+ This is the **master** branch of ActiveModelSerializers.
252
61
 
253
- Serializers will check for the presence of a method named
254
- `include_[ATTRIBUTE]?` to determine whether a particular attribute should be
255
- included in the output. This is typically used to customize output
256
- based on `current_user`. For example:
62
+ It will become the `0.10.0` release when it's ready. Currently this is a release candidate.
257
63
 
258
- ```ruby
259
- class PostSerializer < ActiveModel::Serializer
260
- attributes :id, :title, :body, :author
64
+ `0.10.x` is **not** backward compatible with `0.9.x` nor `0.8.x`.
261
65
 
262
- def include_author?
263
- current_user.admin?
264
- end
265
- end
266
- ```
66
+ `0.10.x` will be based on the `0.8.0` code, but with a more flexible
67
+ architecture. We'd love your help. [Learn how you can help here.](CONTRIBUTING.md)
267
68
 
268
- The type of a computed attribute (like :full_name above) is not easily
269
- calculated without some sophisticated static code analysis. To specify the
270
- type of a computed attribute:
69
+ It is generally safe and recommended to use the master branch.
271
70
 
272
- ```ruby
273
- class PersonSerializer < ActiveModel::Serializer
274
- attributes :first_name, :last_name, {:full_name => :string}
71
+ For more information, see the post '[The future of
72
+ AMS](https://medium.com/@joaomdmoura/the-future-of-ams-e5f9047ca7e9)'.
275
73
 
276
- def full_name
277
- "#{object.first_name} #{object.last_name}"
278
- end
279
- end
280
- ```
74
+ ## Installation
281
75
 
282
- If you would like the key in the outputted JSON to be different from its name
283
- in ActiveRecord, you can use the `:key` option to customize it:
76
+ Add this line to your application's Gemfile:
284
77
 
285
- ```ruby
286
- class PostSerializer < ActiveModel::Serializer
287
- attributes :id, :body
288
-
289
- # look up :subject on the model, but use +title+ in the JSON
290
- attribute :subject, :key => :title
291
- has_many :comments
292
- end
293
78
  ```
294
-
295
- If you would like to add meta information to the outputted JSON, use the `:meta`
296
- option:
297
-
298
- ```ruby
299
- render :json => @posts, :serializer => CustomArraySerializer, :meta => {:total => 10}
79
+ gem 'active_model_serializers'
300
80
  ```
301
81
 
302
- The above usage of `:meta` will produce the following:
82
+ And then execute:
303
83
 
304
- ```json
305
- {
306
- "meta": { "total": 10 },
307
- "posts": [
308
- { "title": "Post 1", "body": "Hello!" },
309
- { "title": "Post 2", "body": "Goodbye!" }
310
- ]
311
- }
312
84
  ```
313
-
314
- If you would like to change the meta key name you can use the `:meta_key` option:
315
-
316
- ```ruby
317
- render :json => @posts, :serializer => CustomArraySerializer, :meta => {:total => 10}, :meta_key => 'meta_object'
318
- ```
319
-
320
- The above usage of `:meta_key` will produce the following:
321
-
322
- ```json
323
- {
324
- "meta_object": { "total": 10 },
325
- "posts": [
326
- { "title": "Post 1", "body": "Hello!" },
327
- { "title": "Post 2", "body": "Goodbye!" }
328
- ]
329
- }
330
- ```
331
-
332
- If you would like direct, low-level control of attribute serialization, you can
333
- completely override the `attributes` method to return the hash you need:
334
-
335
- ```ruby
336
- class PersonSerializer < ActiveModel::Serializer
337
- attributes :first_name, :last_name
338
-
339
- def attributes
340
- hash = super
341
- if current_user.admin?
342
- hash["ssn"] = object.ssn
343
- hash["secret"] = object.mothers_maiden_name
344
- end
345
- hash
346
- end
347
- end
348
- ```
349
-
350
- ## Associations
351
-
352
- For specified associations, the serializer will look up the association and
353
- then serialize each element of the association. For instance, a `has_many
354
- :comments` association will create a new `CommentSerializer` for each comment
355
- and use it to serialize the comment.
356
-
357
- By default, serializers simply look up the association on the original object.
358
- You can customize this behavior by implementing a method with the name of the
359
- association and returning a different Array. Often, you will do this to
360
- customize the objects returned based on the current user.
361
-
362
- ```ruby
363
- class PostSerializer < ActiveModel::Serializer
364
- attributes :id, :title, :body
365
- has_many :comments
366
-
367
- # only let the user see comments he created.
368
- def comments
369
- object.comments.where(:created_by => current_user)
370
- end
371
- end
372
- ```
373
-
374
- As with attributes, you can change the JSON key that the serializer should
375
- use for a particular association.
376
-
377
- ```ruby
378
- class PostSerializer < ActiveModel::Serializer
379
- attributes :id, :title, :body
380
-
381
- # look up comments, but use +my_comments+ as the key in JSON
382
- has_many :comments, :key => :my_comments
383
- end
384
- ```
385
-
386
- Also, as with attributes, serializers will check for the presence
387
- of a method named `include_[ASSOCIATION]?` to determine whether a particular association
388
- should be included in the output. For example:
389
-
390
- ```ruby
391
- class PostSerializer < ActiveModel::Serializer
392
- attributes :id, :title, :body
393
- has_many :comments
394
-
395
- def include_comments?
396
- !object.comments_disabled?
397
- end
398
- end
85
+ $ bundle
399
86
  ```
400
87
 
401
- If you would like lower-level control of association serialization, you can
402
- override `include_associations!` to specify which associations should be included:
88
+ ## Getting Started
403
89
 
404
- ```ruby
405
- class PostSerializer < ActiveModel::Serializer
406
- attributes :id, :title, :body
407
- has_one :author
408
- has_many :comments
409
-
410
- def include_associations!
411
- include! :author if current_user.admin?
412
- include! :comments unless object.comments_disabled?
413
- end
414
- end
415
- ```
90
+ See [Getting Started](docs/general/getting_started.md) for the nuts and bolts.
416
91
 
417
- You may also use the `:serializer` option to specify a custom serializer class and the `:polymorphic` option to specify an association that is polymorphic (STI), e.g.:
92
+ More information is available in the [Guides](docs) and
93
+ [High-level behavior](README.md#high-level-behavior).
418
94
 
419
- ```ruby
420
- has_many :comments, :serializer => CommentShortSerializer
421
- has_one :reviewer, :polymorphic => true
422
- ```
95
+ ## Getting Help
423
96
 
424
- Serializers are only concerned with multiplicity, and not ownership. `belongs_to` ActiveRecord associations can be included using `has_one` in your serializer.
97
+ If you find a bug, please report an [Issue](https://github.com/rails-api/active_model_serializers/issues/new)
98
+ and see our [contributing guide](CONTRIBUTING.md).
425
99
 
426
- ## Embedding Associations
100
+ If you have a question, please [post to Stack Overflow](http://stackoverflow.com/questions/tagged/active-model-serializers).
427
101
 
428
- By default, associations will be embedded inside the serialized object. So if
429
- you have a post, the outputted JSON will look like:
102
+ If you'd like to chat, we have a [community slack](http://amserializers.herokuapp.com).
430
103
 
431
- ```json
432
- {
433
- "post": {
434
- "id": 1,
435
- "title": "New post",
436
- "body": "A body!",
437
- "comments": [
438
- { "id": 1, "body": "what a dumb post" }
439
- ]
440
- }
441
- }
442
- ```
104
+ Thanks!
443
105
 
444
- This is convenient for simple use-cases, but for more complex clients, it is
445
- better to supply an Array of IDs for the association. This makes your API more
446
- flexible from a performance standpoint and avoids wasteful duplication.
106
+ ## High-level behavior
447
107
 
448
- To embed IDs instead of associations, simply use the `embed` class method:
108
+ Given a [serializable model](lib/active_model/serializer/lint.rb):
449
109
 
450
110
  ```ruby
451
- class PostSerializer < ActiveModel::Serializer
452
- embed :ids
453
-
454
- attributes :id, :title, :body
455
- has_many :comments
111
+ # either
112
+ class SomeResource < ActiveRecord::Base
113
+ # columns: title, body
456
114
  end
457
- ```
458
-
459
- Now, any associations will be supplied as an Array of IDs:
460
-
461
- ```json
462
- {
463
- "post": {
464
- "id": 1,
465
- "title": "New post",
466
- "body": "A body!",
467
- "comment_ids": [ 1, 2, 3 ]
468
- }
469
- }
470
- ```
471
-
472
- Alternatively, you can choose to embed only the ids or the associated objects per association:
473
-
474
- ```ruby
475
- class PostSerializer < ActiveModel::Serializer
476
- attributes :id, :title, :body
477
-
478
- has_many :comments, embed: :objects
479
- has_many :tags, embed: :ids
115
+ # or
116
+ class SomeResource < ActiveModelSerializers::Model
117
+ attr_accessor :title, :body
480
118
  end
481
119
  ```
482
120
 
483
- The JSON will look like this:
484
-
485
- ```json
486
- {
487
- "post": {
488
- "id": 1,
489
- "title": "New post",
490
- "body": "A body!",
491
- "comments": [
492
- { "id": 1, "body": "what a dumb post" }
493
- ],
494
- "tag_ids": [ 1, 2, 3 ]
495
- }
496
- }
497
- ```
498
-
499
- In addition to supplying an Array of IDs, you may want to side-load the data
500
- alongside the main object. This makes it easier to process the entire package
501
- of data without having to recursively scan the tree looking for embedded
502
- information. It also ensures that associations that are shared between several
503
- objects (like tags), are only delivered once for the entire payload.
504
-
505
- You can specify that the data be included like this:
121
+ And initialized as:
506
122
 
507
123
  ```ruby
508
- class PostSerializer < ActiveModel::Serializer
509
- embed :ids, :include => true
510
-
511
- attributes :id, :title, :body
512
- has_many :comments
513
- end
514
- ```
515
-
516
- Assuming that the comments also `has_many :tags`, you will get a JSON like
517
- this:
518
-
519
- ```json
520
- {
521
- "post": {
522
- "id": 1,
523
- "title": "New post",
524
- "body": "A body!",
525
- "comment_ids": [ 1, 2 ]
526
- },
527
- "comments": [
528
- { "id": 1, "body": "what a dumb post", "tag_ids": [ 1, 2 ] },
529
- { "id": 2, "body": "i liked it", "tag_ids": [ 1, 3 ] },
530
- ],
531
- "tags": [
532
- { "id": 1, "name": "short" },
533
- { "id": 2, "name": "whiny" },
534
- { "id": 3, "name": "happy" }
535
- ]
536
- }
124
+ resource = SomeResource.new(title: 'ActiveModelSerializers', body: 'Convention over configuration')
537
125
  ```
538
126
 
539
- You can also specify a different root for the embedded objects than the key
540
- used to reference them:
127
+ Given a serializer for the serializable model:
541
128
 
542
129
  ```ruby
543
- class PostSerializer < ActiveModel::Serializer
544
- embed :ids, :include => true
545
-
546
- attributes :id, :title, :body
547
- has_many :comments, :key => :comment_ids, :root => :comment_objects
130
+ class SomeSerializer < ActiveModel::Serializer
131
+ attribute :title, key: :name
132
+ attributes :body
548
133
  end
549
134
  ```
550
135
 
551
- This would generate JSON that would look like this:
552
-
553
- ```json
554
- {
555
- "post": {
556
- "id": 1,
557
- "title": "New post",
558
- "body": "A body!",
559
- "comment_ids": [ 1 ]
560
- },
561
- "comment_objects": [
562
- { "id": 1, "body": "what a dumb post" }
563
- ]
564
- }
565
- ```
566
-
567
- You can also specify a different attribute to use rather than the ID of the
568
- objects:
136
+ The model can be serialized as:
569
137
 
570
138
  ```ruby
571
- class PostSerializer < ActiveModel::Serializer
572
- embed :ids, :include => true
573
-
574
- attributes :id, :title, :body
575
- has_many :comments, :embed_key => :external_id
576
- end
139
+ options = {}
140
+ serialization = ActiveModelSerializers::SerializableResource.new(resource, options)
141
+ serialization.to_json
142
+ serialization.as_json
577
143
  ```
578
144
 
579
- This would generate JSON that would look like this:
580
-
581
- ```json
582
- {
583
- "post": {
584
- "id": 1,
585
- "title": "New post",
586
- "body": "A body!",
587
- "comment_ids": [ "COMM001" ]
588
- },
589
- "comments": [
590
- { "id": 1, "external_id": "COMM001", "body": "what a dumb post" }
591
- ]
592
- }
593
- ```
594
-
595
- **NOTE**: The `embed :ids` mechanism is primary useful for clients that process
596
- data in bulk and load it into a local store. For these clients, the ability to
597
- easily see all of the data per type, rather than having to recursively scan the
598
- data looking for information, is extremely useful.
599
-
600
- If you are mostly working with the data in simple scenarios and manually making
601
- Ajax requests, you probably just want to use the default embedded behavior.
602
-
603
- ## Customizing Scope
604
-
605
- In a serializer, `current_user` is the current authorization scope which the controller
606
- provides to the serializer when you call `render :json`. By default, this is
607
- `current_user`, but can be customized in your controller by calling
608
- `serialization_scope`:
145
+ SerializableResource delegates to the adapter, which it builds as:
609
146
 
610
147
  ```ruby
611
- class ApplicationController < ActionController::Base
612
- serialization_scope :current_admin
613
- end
148
+ adapter_options = {}
149
+ adapter = ActiveModelSerializers::Adapter.create(serializer, adapter_options)
150
+ adapter.to_json
151
+ adapter.as_json
152
+ adapter.serializable_hash
614
153
  ```
615
154
 
616
- The above example will also change the scope name from `current_user` to
617
- `current_admin`.
618
-
619
- Please note that, until now, `serialization_scope` doesn't accept a second
620
- object with options for specifying which actions should or should not take a
621
- given scope in consideration.
622
-
623
- To be clear, it's not possible, yet, to do something like this:
155
+ The adapter formats the serializer's attributes and associations (a.k.a. includes):
624
156
 
625
157
  ```ruby
626
- class SomeController < ApplicationController
627
- serialization_scope :current_admin, :except => [:index, :show]
628
- end
158
+ serializer_options = {}
159
+ serializer = SomeSerializer.new(resource, serializer_options)
160
+ serializer.attributes
161
+ serializer.associations
629
162
  ```
163
+ See [ARCHITECTURE.md](docs/ARCHITECTURE.md) for more information.
630
164
 
631
- So, in order to have a fine grained control of what each action should take in
632
- consideration for its scope, you may use something like this:
633
-
634
- ```ruby
635
- class CitiesController < ApplicationController
636
- serialization_scope nil
637
-
638
- def index
639
- @cities = City.all
640
-
641
- render :json => @cities, :each_serializer => CitySerializer
642
- end
643
-
644
- def show
645
- @city = City.find(params[:id])
646
-
647
- render :json => @city, :scope => current_admin, :scope_name => :current_admin
648
- end
649
- end
650
- ```
165
+ # Contributing
651
166
 
652
- Assuming that the `current_admin` method needs to make a query in the database
653
- for the current user, the advantage of this approach is that, by setting
654
- `serialization_scope` to `nil`, the `index` action no longer will need to make
655
- that query, only the `show` action will.
167
+ See [CONTRIBUTING.md](CONTRIBUTING.md)