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,392 @@
1
+ require 'test_helper'
2
+
3
+ NestedPost = Class.new(Model)
4
+ class NestedPostSerializer < ActiveModel::Serializer
5
+ has_many :nested_posts
6
+ end
7
+
8
+ module ActiveModelSerializers
9
+ module Adapter
10
+ class JsonApi
11
+ class LinkedTest < ActiveSupport::TestCase
12
+ def setup
13
+ @author1 = Author.new(id: 1, name: 'Steve K.')
14
+ @author2 = Author.new(id: 2, name: 'Tenderlove')
15
+ @bio1 = Bio.new(id: 1, content: 'AMS Contributor')
16
+ @bio2 = Bio.new(id: 2, content: 'Rails Contributor')
17
+ @first_post = Post.new(id: 10, title: 'Hello!!', body: 'Hello, world!!')
18
+ @second_post = Post.new(id: 20, title: 'New Post', body: 'Body')
19
+ @third_post = Post.new(id: 30, title: 'Yet Another Post', body: 'Body')
20
+ @blog = Blog.new({ name: 'AMS Blog' })
21
+ @first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
22
+ @second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
23
+ @first_post.blog = @blog
24
+ @second_post.blog = @blog
25
+ @third_post.blog = nil
26
+ @first_post.comments = [@first_comment, @second_comment]
27
+ @second_post.comments = []
28
+ @third_post.comments = []
29
+ @first_post.author = @author1
30
+ @second_post.author = @author2
31
+ @third_post.author = @author1
32
+ @first_comment.post = @first_post
33
+ @first_comment.author = nil
34
+ @second_comment.post = @first_post
35
+ @second_comment.author = nil
36
+ @author1.posts = [@first_post, @third_post]
37
+ @author1.bio = @bio1
38
+ @author1.roles = []
39
+ @author2.posts = [@second_post]
40
+ @author2.bio = @bio2
41
+ @author2.roles = []
42
+ @bio1.author = @author1
43
+ @bio2.author = @author2
44
+ end
45
+
46
+ def test_include_multiple_posts_and_linked_array
47
+ serializer = ActiveModel::Serializer::CollectionSerializer.new([@first_post, @second_post])
48
+ adapter = ActiveModelSerializers::Adapter::JsonApi.new(
49
+ serializer,
50
+ include: [:comments, author: [:bio]]
51
+ )
52
+ alt_adapter = ActiveModelSerializers::Adapter::JsonApi.new(
53
+ serializer,
54
+ include: [:comments, author: [:bio]]
55
+ )
56
+
57
+ expected = {
58
+ data: [
59
+ {
60
+ id: '10',
61
+ type: 'posts',
62
+ attributes: {
63
+ title: 'Hello!!',
64
+ body: 'Hello, world!!'
65
+ },
66
+ relationships: {
67
+ comments: { data: [{ type: 'comments', id: '1' }, { type: 'comments', id: '2' }] },
68
+ blog: { data: { type: 'blogs', id: '999' } },
69
+ author: { data: { type: 'authors', id: '1' } }
70
+ }
71
+ },
72
+ {
73
+ id: '20',
74
+ type: 'posts',
75
+ attributes: {
76
+ title: 'New Post',
77
+ body: 'Body'
78
+ },
79
+ relationships: {
80
+ comments: { data: [] },
81
+ blog: { data: { type: 'blogs', id: '999' } },
82
+ author: { data: { type: 'authors', id: '2' } }
83
+ }
84
+ }
85
+ ],
86
+ included: [
87
+ {
88
+ id: '1',
89
+ type: 'comments',
90
+ attributes: {
91
+ body: 'ZOMG A COMMENT'
92
+ },
93
+ relationships: {
94
+ post: { data: { type: 'posts', id: '10' } },
95
+ author: { data: nil }
96
+ }
97
+ }, {
98
+ id: '2',
99
+ type: 'comments',
100
+ attributes: {
101
+ body: 'ZOMG ANOTHER COMMENT'
102
+ },
103
+ relationships: {
104
+ post: { data: { type: 'posts', id: '10' } },
105
+ author: { data: nil }
106
+ }
107
+ }, {
108
+ id: '1',
109
+ type: 'authors',
110
+ attributes: {
111
+ name: 'Steve K.'
112
+ },
113
+ relationships: {
114
+ posts: { data: [{ type: 'posts', id: '10' }, { type: 'posts', id: '30' }] },
115
+ roles: { data: [] },
116
+ bio: { data: { type: 'bios', id: '1' } }
117
+ }
118
+ }, {
119
+ id: '1',
120
+ type: 'bios',
121
+ attributes: {
122
+ content: 'AMS Contributor',
123
+ rating: nil
124
+ },
125
+ relationships: {
126
+ author: { data: { type: 'authors', id: '1' } }
127
+ }
128
+ }, {
129
+ id: '2',
130
+ type: 'authors',
131
+ attributes: {
132
+ name: 'Tenderlove'
133
+ },
134
+ relationships: {
135
+ posts: { data: [{ type: 'posts', id: '20' }] },
136
+ roles: { data: [] },
137
+ bio: { data: { type: 'bios', id: '2' } }
138
+ }
139
+ }, {
140
+ id: '2',
141
+ type: 'bios',
142
+ attributes: {
143
+ rating: nil,
144
+ content: 'Rails Contributor'
145
+ },
146
+ relationships: {
147
+ author: { data: { type: 'authors', id: '2' } }
148
+ }
149
+ }
150
+ ]
151
+ }
152
+ assert_equal expected, adapter.serializable_hash
153
+ assert_equal expected, alt_adapter.serializable_hash
154
+ end
155
+
156
+ def test_include_multiple_posts_and_linked
157
+ serializer = BioSerializer.new @bio1
158
+ adapter = ActiveModelSerializers::Adapter::JsonApi.new(
159
+ serializer,
160
+ include: [author: [:posts]]
161
+ )
162
+ alt_adapter = ActiveModelSerializers::Adapter::JsonApi.new(
163
+ serializer,
164
+ include: [author: [:posts]]
165
+ )
166
+
167
+ expected = [
168
+ {
169
+ id: '1',
170
+ type: 'authors',
171
+ attributes: {
172
+ name: 'Steve K.'
173
+ },
174
+ relationships: {
175
+ posts: { data: [{ type: 'posts', id: '10' }, { type: 'posts', id: '30' }] },
176
+ roles: { data: [] },
177
+ bio: { data: { type: 'bios', id: '1' } }
178
+ }
179
+ }, {
180
+ id: '10',
181
+ type: 'posts',
182
+ attributes: {
183
+ title: 'Hello!!',
184
+ body: 'Hello, world!!'
185
+ },
186
+ relationships: {
187
+ comments: { data: [{ type: 'comments', id: '1' }, { type: 'comments', id: '2' }] },
188
+ blog: { data: { type: 'blogs', id: '999' } },
189
+ author: { data: { type: 'authors', id: '1' } }
190
+ }
191
+ }, {
192
+ id: '30',
193
+ type: 'posts',
194
+ attributes: {
195
+ title: 'Yet Another Post',
196
+ body: 'Body'
197
+ },
198
+ relationships: {
199
+ comments: { data: [] },
200
+ blog: { data: { type: 'blogs', id: '999' } },
201
+ author: { data: { type: 'authors', id: '1' } }
202
+ }
203
+ }
204
+ ]
205
+
206
+ assert_equal expected, adapter.serializable_hash[:included]
207
+ assert_equal expected, alt_adapter.serializable_hash[:included]
208
+ end
209
+
210
+ def test_underscore_model_namespace_for_linked_resource_type
211
+ spammy_post = Post.new(id: 123)
212
+ spammy_post.related = [Spam::UnrelatedLink.new(id: 456)]
213
+ serializer = SpammyPostSerializer.new(spammy_post)
214
+ adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
215
+ relationships = adapter.serializable_hash[:data][:relationships]
216
+ expected = {
217
+ related: {
218
+ data: [{
219
+ type: 'spam-unrelated-links',
220
+ id: '456'
221
+ }]
222
+ }
223
+ }
224
+ assert_equal expected, relationships
225
+ end
226
+
227
+ def test_multiple_references_to_same_resource
228
+ serializer = ActiveModel::Serializer::CollectionSerializer.new([@first_comment, @second_comment])
229
+ adapter = ActiveModelSerializers::Adapter::JsonApi.new(
230
+ serializer,
231
+ include: [:post]
232
+ )
233
+
234
+ expected = [
235
+ {
236
+ id: '10',
237
+ type: 'posts',
238
+ attributes: {
239
+ title: 'Hello!!',
240
+ body: 'Hello, world!!'
241
+ },
242
+ relationships: {
243
+ comments: {
244
+ data: [{ type: 'comments', id: '1' }, { type: 'comments', id: '2' }]
245
+ },
246
+ blog: {
247
+ data: { type: 'blogs', id: '999' }
248
+ },
249
+ author: {
250
+ data: { type: 'authors', id: '1' }
251
+ }
252
+ }
253
+ }
254
+ ]
255
+
256
+ assert_equal expected, adapter.serializable_hash[:included]
257
+ end
258
+
259
+ def test_nil_link_with_specified_serializer
260
+ @first_post.author = nil
261
+ serializer = PostPreviewSerializer.new(@first_post)
262
+ adapter = ActiveModelSerializers::Adapter::JsonApi.new(
263
+ serializer,
264
+ include: [:author]
265
+ )
266
+
267
+ expected = {
268
+ data: {
269
+ id: '10',
270
+ type: 'posts',
271
+ attributes: {
272
+ title: 'Hello!!',
273
+ body: 'Hello, world!!'
274
+ },
275
+ relationships: {
276
+ comments: { data: [{ type: 'comments', id: '1' }, { type: 'comments', id: '2' }] },
277
+ author: { data: nil }
278
+ }
279
+ }
280
+ }
281
+ assert_equal expected, adapter.serializable_hash
282
+ end
283
+ end
284
+
285
+ class NoDuplicatesTest < ActiveSupport::TestCase
286
+ Post = Class.new(::Model)
287
+ Author = Class.new(::Model)
288
+
289
+ class PostSerializer < ActiveModel::Serializer
290
+ type 'posts'
291
+ belongs_to :author
292
+ end
293
+
294
+ class AuthorSerializer < ActiveModel::Serializer
295
+ type 'authors'
296
+ has_many :posts
297
+ end
298
+
299
+ def setup
300
+ @author = Author.new(id: 1, posts: [], roles: [], bio: nil)
301
+ @post1 = Post.new(id: 1, author: @author)
302
+ @post2 = Post.new(id: 2, author: @author)
303
+ @author.posts << @post1
304
+ @author.posts << @post2
305
+
306
+ @nestedpost1 = ::NestedPost.new(id: 1, nested_posts: [])
307
+ @nestedpost2 = ::NestedPost.new(id: 2, nested_posts: [])
308
+ @nestedpost1.nested_posts << @nestedpost1
309
+ @nestedpost1.nested_posts << @nestedpost2
310
+ @nestedpost2.nested_posts << @nestedpost1
311
+ @nestedpost2.nested_posts << @nestedpost2
312
+ end
313
+
314
+ def test_no_duplicates
315
+ hash = ActiveModelSerializers::SerializableResource.new(@post1, adapter: :json_api,
316
+ include: '*.*')
317
+ .serializable_hash
318
+ expected = [
319
+ {
320
+ type: 'authors', id: '1',
321
+ relationships: {
322
+ posts: {
323
+ data: [
324
+ { type: 'posts', id: '1' },
325
+ { type: 'posts', id: '2' }
326
+ ]
327
+ }
328
+ }
329
+ },
330
+ {
331
+ type: 'posts', id: '2',
332
+ relationships: {
333
+ author: {
334
+ data: { type: 'authors', id: '1' }
335
+ }
336
+ }
337
+ }
338
+ ]
339
+ assert_equal(expected, hash[:included])
340
+ end
341
+
342
+ def test_no_duplicates_collection
343
+ hash = ActiveModelSerializers::SerializableResource.new(
344
+ [@post1, @post2], adapter: :json_api,
345
+ include: '*.*')
346
+ .serializable_hash
347
+ expected = [
348
+ {
349
+ type: 'authors', id: '1',
350
+ relationships: {
351
+ posts: {
352
+ data: [
353
+ { type: 'posts', id: '1' },
354
+ { type: 'posts', id: '2' }
355
+ ]
356
+ }
357
+ }
358
+ }
359
+ ]
360
+ assert_equal(expected, hash[:included])
361
+ end
362
+
363
+ def test_no_duplicates_global
364
+ hash = ActiveModelSerializers::SerializableResource.new(
365
+ @nestedpost1,
366
+ adapter: :json_api,
367
+ include: '*').serializable_hash
368
+ expected = [
369
+ type: 'nested-posts', id: '2',
370
+ relationships: {
371
+ :"nested-posts" => {
372
+ data: [
373
+ { type: 'nested-posts', id: '1' },
374
+ { type: 'nested-posts', id: '2' }
375
+ ]
376
+ }
377
+ }
378
+ ]
379
+ assert_equal(expected, hash[:included])
380
+ end
381
+
382
+ def test_no_duplicates_collection_global
383
+ hash = ActiveModelSerializers::SerializableResource.new(
384
+ [@nestedpost1, @nestedpost2],
385
+ adapter: :json_api,
386
+ include: '*').serializable_hash
387
+ assert_nil(hash[:included])
388
+ end
389
+ end
390
+ end
391
+ end
392
+ end
@@ -0,0 +1,93 @@
1
+ require 'test_helper'
2
+
3
+ module ActiveModelSerializers
4
+ module Adapter
5
+ class JsonApi
6
+ class LinksTest < ActiveSupport::TestCase
7
+ LinkAuthor = Class.new(::Model)
8
+ class LinkAuthorSerializer < ActiveModel::Serializer
9
+ link :self do
10
+ href "http://example.com/link_author/#{object.id}"
11
+ meta stuff: 'value'
12
+ end
13
+ link(:author) { link_author_url(object.id) }
14
+ link(:link_authors) { url_for(controller: 'link_authors', action: 'index', only_path: false) }
15
+ link(:posts) { link_author_posts_url(object.id) }
16
+ link :resource, 'http://example.com/resource'
17
+ link :yet_another do
18
+ "http://example.com/resource/#{object.id}"
19
+ end
20
+ end
21
+
22
+ def setup
23
+ Rails.application.routes.draw do
24
+ resources :link_authors do
25
+ resources :posts
26
+ end
27
+ end
28
+ @post = Post.new(id: 1337, comments: [], author: nil)
29
+ @author = LinkAuthor.new(id: 1337, posts: [@post])
30
+ end
31
+
32
+ def test_toplevel_links
33
+ hash = ActiveModelSerializers::SerializableResource.new(
34
+ @post,
35
+ adapter: :json_api,
36
+ links: {
37
+ self: {
38
+ href: 'http://example.com/posts',
39
+ meta: {
40
+ stuff: 'value'
41
+ }
42
+ }
43
+ }).serializable_hash
44
+ expected = {
45
+ self: {
46
+ href: 'http://example.com/posts',
47
+ meta: {
48
+ stuff: 'value'
49
+ }
50
+ }
51
+ }
52
+ assert_equal(expected, hash[:links])
53
+ end
54
+
55
+ def test_nil_toplevel_links
56
+ hash = ActiveModelSerializers::SerializableResource.new(
57
+ @post,
58
+ adapter: :json_api,
59
+ links: nil
60
+ ).serializable_hash
61
+ refute hash.key?(:links), 'No links key to be output'
62
+ end
63
+
64
+ def test_nil_toplevel_links_json_adapter
65
+ hash = ActiveModelSerializers::SerializableResource.new(
66
+ @post,
67
+ adapter: :json,
68
+ links: nil
69
+ ).serializable_hash
70
+ refute hash.key?(:links), 'No links key to be output'
71
+ end
72
+
73
+ def test_resource_links
74
+ hash = serializable(@author, adapter: :json_api).serializable_hash
75
+ expected = {
76
+ self: {
77
+ href: 'http://example.com/link_author/1337',
78
+ meta: {
79
+ stuff: 'value'
80
+ }
81
+ },
82
+ author: 'http://example.com/link_authors/1337',
83
+ :"link-authors" => 'http://example.com/link_authors',
84
+ resource: 'http://example.com/resource',
85
+ posts: 'http://example.com/link_authors/1337/posts',
86
+ :"yet-another" => 'http://example.com/resource/1337'
87
+ }
88
+ assert_equal(expected, hash[:data][:links])
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,166 @@
1
+ require 'test_helper'
2
+ require 'will_paginate/array'
3
+ require 'kaminari'
4
+ require 'kaminari/hooks'
5
+ ::Kaminari::Hooks.init
6
+
7
+ module ActiveModelSerializers
8
+ module Adapter
9
+ class JsonApi
10
+ class PaginationLinksTest < ActiveSupport::TestCase
11
+ URI = 'http://example.com'.freeze
12
+
13
+ def setup
14
+ ActionController::Base.cache_store.clear
15
+ @array = [
16
+ Profile.new({ id: 1, name: 'Name 1', description: 'Description 1', comments: 'Comments 1' }),
17
+ Profile.new({ id: 2, name: 'Name 2', description: 'Description 2', comments: 'Comments 2' }),
18
+ Profile.new({ id: 3, name: 'Name 3', description: 'Description 3', comments: 'Comments 3' }),
19
+ Profile.new({ id: 4, name: 'Name 4', description: 'Description 4', comments: 'Comments 4' }),
20
+ Profile.new({ id: 5, name: 'Name 5', description: 'Description 5', comments: 'Comments 5' })
21
+ ]
22
+ end
23
+
24
+ def mock_request(query_parameters = {}, original_url = URI)
25
+ context = Minitest::Mock.new
26
+ context.expect(:request_url, original_url)
27
+ context.expect(:query_parameters, query_parameters)
28
+ context.expect(:key_transform, nil)
29
+ end
30
+
31
+ def load_adapter(paginated_collection, mock_request = nil)
32
+ render_options = { adapter: :json_api }
33
+ render_options[:serialization_context] = mock_request if mock_request
34
+ serializable(paginated_collection, render_options)
35
+ end
36
+
37
+ def using_kaminari(page = 2)
38
+ Kaminari.paginate_array(@array).page(page).per(2)
39
+ end
40
+
41
+ def using_will_paginate(page = 2)
42
+ @array.paginate(page: page, per_page: 2)
43
+ end
44
+
45
+ def data
46
+ { data: [
47
+ { id: '1', type: 'profiles', attributes: { name: 'Name 1', description: 'Description 1' } },
48
+ { id: '2', type: 'profiles', attributes: { name: 'Name 2', description: 'Description 2' } },
49
+ { id: '3', type: 'profiles', attributes: { name: 'Name 3', description: 'Description 3' } },
50
+ { id: '4', type: 'profiles', attributes: { name: 'Name 4', description: 'Description 4' } },
51
+ { id: '5', type: 'profiles', attributes: { name: 'Name 5', description: 'Description 5' } }
52
+ ]
53
+ }
54
+ end
55
+
56
+ def links
57
+ {
58
+ links: {
59
+ self: "#{URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2",
60
+ first: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
61
+ prev: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
62
+ next: "#{URI}?page%5Bnumber%5D=3&page%5Bsize%5D=2",
63
+ last: "#{URI}?page%5Bnumber%5D=3&page%5Bsize%5D=2"
64
+ }
65
+ }
66
+ end
67
+
68
+ def last_page_links
69
+ {
70
+ links: {
71
+ self: "#{URI}?page%5Bnumber%5D=3&page%5Bsize%5D=2",
72
+ first: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
73
+ prev: "#{URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2"
74
+ }
75
+ }
76
+ end
77
+
78
+ def expected_response_without_pagination_links
79
+ data
80
+ end
81
+
82
+ def expected_response_with_pagination_links
83
+ {}.tap do |hash|
84
+ hash[:data] = data.values.flatten[2..3]
85
+ hash.merge! links
86
+ end
87
+ end
88
+
89
+ def expected_response_with_pagination_links_and_additional_params
90
+ new_links = links[:links].each_with_object({}) { |(key, value), hash| hash[key] = "#{value}&test=test" }
91
+ {}.tap do |hash|
92
+ hash[:data] = data.values.flatten[2..3]
93
+ hash.merge! links: new_links
94
+ end
95
+ end
96
+
97
+ def expected_response_with_last_page_pagination_links
98
+ {}.tap do |hash|
99
+ hash[:data] = [data.values.flatten.last]
100
+ hash.merge! last_page_links
101
+ end
102
+ end
103
+
104
+ def expected_response_with_no_data_pagination_links
105
+ {}.tap do |hash|
106
+ hash[:data] = []
107
+ hash[:links] = {}
108
+ end
109
+ end
110
+
111
+ def test_pagination_links_using_kaminari
112
+ adapter = load_adapter(using_kaminari, mock_request)
113
+
114
+ assert_equal expected_response_with_pagination_links, adapter.serializable_hash
115
+ end
116
+
117
+ def test_pagination_links_using_will_paginate
118
+ adapter = load_adapter(using_will_paginate, mock_request)
119
+
120
+ assert_equal expected_response_with_pagination_links, adapter.serializable_hash
121
+ end
122
+
123
+ def test_pagination_links_with_additional_params
124
+ adapter = load_adapter(using_will_paginate, mock_request({ test: 'test' }))
125
+
126
+ assert_equal expected_response_with_pagination_links_and_additional_params,
127
+ adapter.serializable_hash
128
+ end
129
+
130
+ def test_pagination_links_when_zero_results_kaminari
131
+ @array = []
132
+
133
+ adapter = load_adapter(using_kaminari(1), mock_request)
134
+
135
+ assert_equal expected_response_with_no_data_pagination_links, adapter.serializable_hash
136
+ end
137
+
138
+ def test_pagination_links_when_zero_results_will_paginate
139
+ @array = []
140
+
141
+ adapter = load_adapter(using_will_paginate(1), mock_request)
142
+
143
+ assert_equal expected_response_with_no_data_pagination_links, adapter.serializable_hash
144
+ end
145
+
146
+ def test_last_page_pagination_links_using_kaminari
147
+ adapter = load_adapter(using_kaminari(3), mock_request)
148
+
149
+ assert_equal expected_response_with_last_page_pagination_links, adapter.serializable_hash
150
+ end
151
+
152
+ def test_last_page_pagination_links_using_will_paginate
153
+ adapter = load_adapter(using_will_paginate(3), mock_request)
154
+
155
+ assert_equal expected_response_with_last_page_pagination_links, adapter.serializable_hash
156
+ end
157
+
158
+ def test_not_showing_pagination_links
159
+ adapter = load_adapter(@array, mock_request)
160
+
161
+ assert_equal expected_response_without_pagination_links, adapter.serializable_hash
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end