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,134 @@
1
+ require 'test_helper'
2
+
3
+ module ActionController
4
+ module Serialization
5
+ class ExplicitSerializerTest < ActionController::TestCase
6
+ class ExplicitSerializerTestController < ActionController::Base
7
+ def render_using_explicit_serializer
8
+ @profile = Profile.new(name: 'Name 1',
9
+ description: 'Description 1',
10
+ comments: 'Comments 1')
11
+ render json: @profile, serializer: ProfilePreviewSerializer
12
+ end
13
+
14
+ def render_array_using_explicit_serializer
15
+ array = [
16
+ Profile.new(name: 'Name 1',
17
+ description: 'Description 1',
18
+ comments: 'Comments 1'),
19
+ Profile.new(name: 'Name 2',
20
+ description: 'Description 2',
21
+ comments: 'Comments 2')
22
+ ]
23
+ render json: array,
24
+ serializer: PaginatedSerializer,
25
+ each_serializer: ProfilePreviewSerializer
26
+ end
27
+
28
+ def render_array_using_implicit_serializer
29
+ array = [
30
+ Profile.new(name: 'Name 1',
31
+ description: 'Description 1',
32
+ comments: 'Comments 1'),
33
+ Profile.new(name: 'Name 2',
34
+ description: 'Description 2',
35
+ comments: 'Comments 2')
36
+ ]
37
+ render json: array,
38
+ each_serializer: ProfilePreviewSerializer
39
+ end
40
+
41
+ def render_array_using_explicit_serializer_and_custom_serializers
42
+ @post = Post.new(title: 'New Post', body: 'Body')
43
+ @author = Author.new(name: 'Jane Blogger')
44
+ @author.posts = [@post]
45
+ @post.author = @author
46
+ @first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
47
+ @second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
48
+ @post.comments = [@first_comment, @second_comment]
49
+ @first_comment.post = @post
50
+ @first_comment.author = nil
51
+ @second_comment.post = @post
52
+ @second_comment.author = nil
53
+ @blog = Blog.new(id: 23, name: 'AMS Blog')
54
+ @post.blog = @blog
55
+
56
+ render json: [@post], each_serializer: PostPreviewSerializer
57
+ end
58
+
59
+ def render_using_explicit_each_serializer
60
+ location = Location.new(id: 42, lat: '-23.550520', lng: '-46.633309')
61
+ place = Place.new(id: 1337, name: 'Amazing Place', locations: [location])
62
+
63
+ render json: place, each_serializer: PlaceSerializer
64
+ end
65
+ end
66
+
67
+ tests ExplicitSerializerTestController
68
+
69
+ def test_render_using_explicit_serializer
70
+ get :render_using_explicit_serializer
71
+
72
+ assert_equal 'application/json', @response.content_type
73
+ assert_equal '{"name":"Name 1"}', @response.body
74
+ end
75
+
76
+ def test_render_array_using_explicit_serializer
77
+ get :render_array_using_explicit_serializer
78
+ assert_equal 'application/json', @response.content_type
79
+
80
+ expected = [
81
+ { 'name' => 'Name 1' },
82
+ { 'name' => 'Name 2' }
83
+ ]
84
+
85
+ assert_equal expected.to_json, @response.body
86
+ end
87
+
88
+ def test_render_array_using_implicit_serializer
89
+ get :render_array_using_implicit_serializer
90
+ assert_equal 'application/json', @response.content_type
91
+
92
+ expected = [
93
+ { 'name' => 'Name 1' },
94
+ { 'name' => 'Name 2' }
95
+ ]
96
+ assert_equal expected.to_json, @response.body
97
+ end
98
+
99
+ def test_render_array_using_explicit_serializer_and_custom_serializers
100
+ get :render_array_using_explicit_serializer_and_custom_serializers
101
+
102
+ expected = [
103
+ { 'title' => 'New Post',
104
+ 'body' => 'Body',
105
+ 'id' => assigns(:post).id,
106
+ 'comments' => [{ 'id' => 1 }, { 'id' => 2 }],
107
+ 'author' => { 'id' => assigns(:author).id }
108
+ }
109
+ ]
110
+
111
+ assert_equal expected.to_json, @response.body
112
+ end
113
+
114
+ def test_render_using_explicit_each_serializer
115
+ get :render_using_explicit_each_serializer
116
+
117
+ expected = {
118
+ id: 1337,
119
+ name: 'Amazing Place',
120
+ locations: [
121
+ {
122
+ id: 42,
123
+ lat: '-23.550520',
124
+ lng: '-46.633309',
125
+ place: 'Nowhere' # is a virtual attribute on LocationSerializer
126
+ }
127
+ ]
128
+ }
129
+
130
+ assert_equal expected.to_json, response.body
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,167 @@
1
+ require 'test_helper'
2
+
3
+ module ActionController
4
+ module Serialization
5
+ class Json
6
+ class IncludeTest < ActionController::TestCase
7
+ class IncludeTestController < ActionController::Base
8
+ def setup_data
9
+ ActionController::Base.cache_store.clear
10
+
11
+ @author = Author.new(id: 1, name: 'Steve K.')
12
+
13
+ @post = Post.new(id: 42, title: 'New Post', body: 'Body')
14
+ @first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
15
+ @second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
16
+
17
+ @post.comments = [@first_comment, @second_comment]
18
+ @post.author = @author
19
+
20
+ @first_comment.post = @post
21
+ @second_comment.post = @post
22
+
23
+ @blog = Blog.new(id: 1, name: 'My Blog!!')
24
+ @post.blog = @blog
25
+ @author.posts = [@post]
26
+
27
+ @first_comment.author = @author
28
+ @second_comment.author = @author
29
+ @author.comments = [@first_comment, @second_comment]
30
+ @author.roles = []
31
+ @author.bio = {}
32
+ end
33
+
34
+ def render_without_include
35
+ setup_data
36
+ render json: @author, adapter: :json
37
+ end
38
+
39
+ def render_resource_with_include_hash
40
+ setup_data
41
+ render json: @author, include: { posts: :comments }, adapter: :json
42
+ end
43
+
44
+ def render_resource_with_include_string
45
+ setup_data
46
+ render json: @author, include: 'posts.comments', adapter: :json
47
+ end
48
+
49
+ def render_resource_with_deep_include
50
+ setup_data
51
+ render json: @author, include: 'posts.comments.author', adapter: :json
52
+ end
53
+ end
54
+
55
+ tests IncludeTestController
56
+
57
+ def test_render_without_include
58
+ get :render_without_include
59
+ response = JSON.parse(@response.body)
60
+ expected = {
61
+ 'author' => {
62
+ 'id' => 1,
63
+ 'name' => 'Steve K.',
64
+ 'posts' => [
65
+ {
66
+ 'id' => 42, 'title' => 'New Post', 'body' => 'Body'
67
+ }
68
+ ],
69
+ 'roles' => [],
70
+ 'bio' => {}
71
+ }
72
+ }
73
+
74
+ assert_equal(expected, response)
75
+ end
76
+
77
+ def test_render_resource_with_include_hash
78
+ get :render_resource_with_include_hash
79
+ response = JSON.parse(@response.body)
80
+ expected = {
81
+ 'author' => {
82
+ 'id' => 1,
83
+ 'name' => 'Steve K.',
84
+ 'posts' => [
85
+ {
86
+ 'id' => 42, 'title' => 'New Post', 'body' => 'Body',
87
+ 'comments' => [
88
+ {
89
+ 'id' => 1, 'body' => 'ZOMG A COMMENT'
90
+ },
91
+ {
92
+ 'id' => 2, 'body' => 'ZOMG ANOTHER COMMENT'
93
+ }
94
+ ]
95
+ }
96
+ ]
97
+ }
98
+ }
99
+
100
+ assert_equal(expected, response)
101
+ end
102
+
103
+ def test_render_resource_with_include_string
104
+ get :render_resource_with_include_string
105
+
106
+ response = JSON.parse(@response.body)
107
+ expected = {
108
+ 'author' => {
109
+ 'id' => 1,
110
+ 'name' => 'Steve K.',
111
+ 'posts' => [
112
+ {
113
+ 'id' => 42, 'title' => 'New Post', 'body' => 'Body',
114
+ 'comments' => [
115
+ {
116
+ 'id' => 1, 'body' => 'ZOMG A COMMENT'
117
+ },
118
+ {
119
+ 'id' => 2, 'body' => 'ZOMG ANOTHER COMMENT'
120
+ }
121
+ ]
122
+ }
123
+ ]
124
+ }
125
+ }
126
+
127
+ assert_equal(expected, response)
128
+ end
129
+
130
+ def test_render_resource_with_deep_include
131
+ get :render_resource_with_deep_include
132
+
133
+ response = JSON.parse(@response.body)
134
+ expected = {
135
+ 'author' => {
136
+ 'id' => 1,
137
+ 'name' => 'Steve K.',
138
+ 'posts' => [
139
+ {
140
+ 'id' => 42, 'title' => 'New Post', 'body' => 'Body',
141
+ 'comments' => [
142
+ {
143
+ 'id' => 1, 'body' => 'ZOMG A COMMENT',
144
+ 'author' => {
145
+ 'id' => 1,
146
+ 'name' => 'Steve K.'
147
+ }
148
+ },
149
+ {
150
+ 'id' => 2, 'body' => 'ZOMG ANOTHER COMMENT',
151
+ 'author' => {
152
+ 'id' => 1,
153
+ 'name' => 'Steve K.'
154
+ }
155
+ }
156
+ ]
157
+ }
158
+ ]
159
+ }
160
+ }
161
+
162
+ assert_equal(expected, response)
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,112 @@
1
+ require 'test_helper'
2
+
3
+ module ActionController
4
+ module Serialization
5
+ class JsonApi
6
+ class DeserializationTest < ActionController::TestCase
7
+ class DeserializationTestController < ActionController::Base
8
+ def render_parsed_payload
9
+ parsed_hash = ActiveModelSerializers::Deserialization.jsonapi_parse(params)
10
+ render json: parsed_hash
11
+ end
12
+
13
+ def render_polymorphic_parsed_payload
14
+ parsed_hash = ActiveModelSerializers::Deserialization.jsonapi_parse(
15
+ params,
16
+ polymorphic: [:restriction_for, :restricted_to]
17
+ )
18
+ render json: parsed_hash
19
+ end
20
+ end
21
+
22
+ tests DeserializationTestController
23
+
24
+ def test_deserialization_of_relationship_only_object
25
+ hash = {
26
+ 'data' => {
27
+ 'type' => 'restraints',
28
+ 'relationships' => {
29
+ 'restriction_for' => {
30
+ 'data' => {
31
+ 'type' => 'discounts',
32
+ 'id' => '67'
33
+ }
34
+ },
35
+ 'restricted_to' => {
36
+ 'data' => nil
37
+ }
38
+ }
39
+ },
40
+ 'restraint' => {}
41
+ }
42
+
43
+ post :render_polymorphic_parsed_payload, params: hash
44
+
45
+ response = JSON.parse(@response.body)
46
+ expected = {
47
+ 'restriction_for_id' => '67',
48
+ 'restriction_for_type' => 'discounts',
49
+ 'restricted_to_id' => nil,
50
+ 'restricted_to_type' => nil
51
+ }
52
+
53
+ assert_equal(expected, response)
54
+ end
55
+
56
+ def test_deserialization
57
+ hash = {
58
+ 'data' => {
59
+ 'type' => 'photos',
60
+ 'id' => 'zorglub',
61
+ 'attributes' => {
62
+ 'title' => 'Ember Hamster',
63
+ 'src' => 'http://example.com/images/productivity.png',
64
+ 'image-width' => '200',
65
+ 'imageHeight' => '200',
66
+ 'ImageSize' => '1024'
67
+ },
68
+ 'relationships' => {
69
+ 'author' => {
70
+ 'data' => nil
71
+ },
72
+ 'photographer' => {
73
+ 'data' => { 'type' => 'people', 'id' => '9' }
74
+ },
75
+ 'comments' => {
76
+ 'data' => [
77
+ { 'type' => 'comments', 'id' => '1' },
78
+ { 'type' => 'comments', 'id' => '2' }
79
+ ]
80
+ },
81
+ 'related-images' => {
82
+ 'data' => [
83
+ { 'type' => 'image', 'id' => '7' },
84
+ { 'type' => 'image', 'id' => '8' }
85
+ ]
86
+ }
87
+ }
88
+ }
89
+ }
90
+
91
+ post :render_parsed_payload, params: hash
92
+
93
+ response = JSON.parse(@response.body)
94
+ expected = {
95
+ 'id' => 'zorglub',
96
+ 'title' => 'Ember Hamster',
97
+ 'src' => 'http://example.com/images/productivity.png',
98
+ 'image_width' => '200',
99
+ 'image_height' => '200',
100
+ 'image_size' => '1024',
101
+ 'author_id' => nil,
102
+ 'photographer_id' => '9',
103
+ 'comment_ids' => %w(1 2),
104
+ 'related_image_ids' => %w(7 8)
105
+ }
106
+
107
+ assert_equal(expected, response)
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,41 @@
1
+ require 'test_helper'
2
+
3
+ module ActionController
4
+ module Serialization
5
+ class JsonApi
6
+ class ErrorsTest < ActionController::TestCase
7
+ def test_active_model_with_multiple_errors
8
+ get :render_resource_with_errors
9
+
10
+ expected_errors_object =
11
+ { :errors =>
12
+ [
13
+ { :source => { :pointer => '/data/attributes/name' }, :detail => 'cannot be nil' },
14
+ { :source => { :pointer => '/data/attributes/name' }, :detail => 'must be longer' },
15
+ { :source => { :pointer => '/data/attributes/id' }, :detail => 'must be a uuid' }
16
+ ]
17
+ }.to_json
18
+ assert_equal json_reponse_body.to_json, expected_errors_object
19
+ end
20
+
21
+ def json_reponse_body
22
+ JSON.load(@response.body)
23
+ end
24
+
25
+ class ErrorsTestController < ActionController::Base
26
+ def render_resource_with_errors
27
+ resource = Profile.new(name: 'Name 1',
28
+ description: 'Description 1',
29
+ comments: 'Comments 1')
30
+ resource.errors.add(:name, 'cannot be nil')
31
+ resource.errors.add(:name, 'must be longer')
32
+ resource.errors.add(:id, 'must be a uuid')
33
+ render json: resource, adapter: :json_api, serializer: ActiveModel::Serializer::ErrorSerializer
34
+ end
35
+ end
36
+
37
+ tests ErrorsTestController
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,197 @@
1
+ require 'test_helper'
2
+
3
+ module ActionController
4
+ module Serialization
5
+ class JsonApi
6
+ class LinkedTest < ActionController::TestCase
7
+ class LinkedTestController < ActionController::Base
8
+ require 'active_model_serializers/register_jsonapi_renderer'
9
+ def setup_post
10
+ ActionController::Base.cache_store.clear
11
+ @role1 = Role.new(id: 1, name: 'admin')
12
+ @role2 = Role.new(id: 2, name: 'colab')
13
+ @author = Author.new(id: 1, name: 'Steve K.')
14
+ @author.posts = []
15
+ @author.bio = nil
16
+ @author.roles = [@role1, @role2]
17
+ @role1.author = @author
18
+ @role2.author = @author
19
+ @author2 = Author.new(id: 2, name: 'Anonymous')
20
+ @author2.posts = []
21
+ @author2.bio = nil
22
+ @author2.roles = []
23
+ @post = Post.new(id: 1, title: 'New Post', body: 'Body')
24
+ @first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
25
+ @second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
26
+ @post.comments = [@first_comment, @second_comment]
27
+ @post.author = @author
28
+ @first_comment.post = @post
29
+ @first_comment.author = @author2
30
+ @second_comment.post = @post
31
+ @second_comment.author = nil
32
+ @post2 = Post.new(id: 2, title: 'Another Post', body: 'Body')
33
+ @post2.author = @author
34
+ @post2.comments = []
35
+ @blog = Blog.new(id: 1, name: 'My Blog!!')
36
+ @post.blog = @blog
37
+ @post2.blog = @blog
38
+ end
39
+
40
+ def render_resource_without_include
41
+ setup_post
42
+ render jsonapi: @post
43
+ end
44
+
45
+ def render_resource_with_include
46
+ setup_post
47
+ render jsonapi: @post, include: [:author]
48
+ end
49
+
50
+ def render_resource_with_include_of_custom_key_by_original
51
+ setup_post
52
+ render jsonapi: @post, include: [:reviews], serializer: PostWithCustomKeysSerializer
53
+ end
54
+
55
+ def render_resource_with_nested_include
56
+ setup_post
57
+ render jsonapi: @post, include: [comments: [:author]]
58
+ end
59
+
60
+ def render_resource_with_nested_has_many_include_wildcard
61
+ setup_post
62
+ render jsonapi: @post, include: 'author.*'
63
+ end
64
+
65
+ def render_resource_with_missing_nested_has_many_include
66
+ setup_post
67
+ @post.author = @author2 # author2 has no roles.
68
+ render jsonapi: @post, include: [author: [:roles]]
69
+ end
70
+
71
+ def render_collection_with_missing_nested_has_many_include
72
+ setup_post
73
+ @post.author = @author2
74
+ render jsonapi: [@post, @post2], include: [author: [:roles]]
75
+ end
76
+
77
+ def render_collection_without_include
78
+ setup_post
79
+ render jsonapi: [@post]
80
+ end
81
+
82
+ def render_collection_with_include
83
+ setup_post
84
+ render jsonapi: [@post], include: 'author, comments'
85
+ end
86
+ end
87
+
88
+ tests LinkedTestController
89
+
90
+ def test_render_resource_without_include
91
+ get :render_resource_without_include
92
+ response = JSON.parse(@response.body)
93
+ refute response.key? 'included'
94
+ end
95
+
96
+ def test_render_resource_with_include
97
+ get :render_resource_with_include
98
+ response = JSON.parse(@response.body)
99
+ assert response.key? 'included'
100
+ assert_equal 1, response['included'].size
101
+ assert_equal 'Steve K.', response['included'].first['attributes']['name']
102
+ end
103
+
104
+ def test_render_resource_with_nested_has_many_include
105
+ get :render_resource_with_nested_has_many_include_wildcard
106
+ response = JSON.parse(@response.body)
107
+ expected_linked = [
108
+ {
109
+ 'id' => '1',
110
+ 'type' => 'authors',
111
+ 'attributes' => {
112
+ 'name' => 'Steve K.'
113
+ },
114
+ 'relationships' => {
115
+ 'posts' => { 'data' => [] },
116
+ 'roles' => { 'data' => [{ 'type' => 'roles', 'id' => '1' }, { 'type' => 'roles', 'id' => '2' }] },
117
+ 'bio' => { 'data' => nil }
118
+ }
119
+ }, {
120
+ 'id' => '1',
121
+ 'type' => 'roles',
122
+ 'attributes' => {
123
+ 'name' => 'admin',
124
+ 'description' => nil,
125
+ 'slug' => 'admin-1'
126
+ },
127
+ 'relationships' => {
128
+ 'author' => { 'data' => { 'type' => 'authors', 'id' => '1' } }
129
+ }
130
+ }, {
131
+ 'id' => '2',
132
+ 'type' => 'roles',
133
+ 'attributes' => {
134
+ 'name' => 'colab',
135
+ 'description' => nil,
136
+ 'slug' => 'colab-2'
137
+ },
138
+ 'relationships' => {
139
+ 'author' => { 'data' => { 'type' => 'authors', 'id' => '1' } }
140
+ }
141
+ }
142
+ ]
143
+ assert_equal expected_linked, response['included']
144
+ end
145
+
146
+ def test_render_resource_with_include_of_custom_key_by_original
147
+ get :render_resource_with_include_of_custom_key_by_original
148
+ response = JSON.parse(@response.body)
149
+ assert response.key? 'included'
150
+
151
+ relationships = response['data']['relationships']
152
+
153
+ assert_includes relationships, 'reviews'
154
+ assert_includes relationships, 'writer'
155
+ assert_includes relationships, 'site'
156
+ end
157
+
158
+ def test_render_resource_with_nested_include
159
+ get :render_resource_with_nested_include
160
+ response = JSON.parse(@response.body)
161
+ assert response.key? 'included'
162
+ assert_equal 3, response['included'].size
163
+ end
164
+
165
+ def test_render_collection_without_include
166
+ get :render_collection_without_include
167
+ response = JSON.parse(@response.body)
168
+ refute response.key? 'included'
169
+ end
170
+
171
+ def test_render_collection_with_include
172
+ get :render_collection_with_include
173
+ response = JSON.parse(@response.body)
174
+ assert response.key? 'included'
175
+ end
176
+
177
+ def test_render_resource_with_nested_attributes_even_when_missing_associations
178
+ get :render_resource_with_missing_nested_has_many_include
179
+ response = JSON.parse(@response.body)
180
+ assert response.key? 'included'
181
+ refute has_type?(response['included'], 'roles')
182
+ end
183
+
184
+ def test_render_collection_with_missing_nested_has_many_include
185
+ get :render_collection_with_missing_nested_has_many_include
186
+ response = JSON.parse(@response.body)
187
+ assert response.key? 'included'
188
+ assert has_type?(response['included'], 'roles')
189
+ end
190
+
191
+ def has_type?(collection, value)
192
+ collection.detect { |i| i['type'] == value }
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end