active_model_serializers 0.8.3 → 0.10.0.rc4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (184) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -0
  3. data/.rubocop.yml +86 -0
  4. data/.rubocop_todo.yml +240 -0
  5. data/.simplecov +111 -0
  6. data/.travis.yml +33 -22
  7. data/CHANGELOG.md +358 -6
  8. data/CONTRIBUTING.md +220 -0
  9. data/Gemfile +46 -1
  10. data/{MIT-LICENSE.txt → LICENSE.txt} +3 -2
  11. data/README.md +81 -591
  12. data/Rakefile +68 -11
  13. data/active_model_serializers.gemspec +57 -23
  14. data/appveyor.yml +27 -0
  15. data/docs/ARCHITECTURE.md +120 -0
  16. data/docs/DESIGN.textile +8 -0
  17. data/docs/README.md +35 -0
  18. data/docs/general/adapters.md +162 -0
  19. data/docs/general/caching.md +52 -0
  20. data/docs/general/configuration_options.md +27 -0
  21. data/docs/general/getting_started.md +98 -0
  22. data/docs/general/instrumentation.md +40 -0
  23. data/docs/general/logging.md +14 -0
  24. data/docs/general/rendering.md +153 -0
  25. data/docs/general/serializers.md +207 -0
  26. data/docs/how-open-source-maintained.jpg +0 -0
  27. data/docs/howto/add_pagination_links.md +121 -0
  28. data/docs/howto/add_root_key.md +51 -0
  29. data/docs/howto/outside_controller_use.md +58 -0
  30. data/docs/howto/test.md +152 -0
  31. data/docs/integrations/ember-and-json-api.md +112 -0
  32. data/docs/integrations/grape.md +19 -0
  33. data/docs/jsonapi/schema/schema.json +366 -0
  34. data/docs/jsonapi/schema.md +140 -0
  35. data/lib/action_controller/serialization.rb +41 -37
  36. data/lib/active_model/serializable_resource.rb +72 -0
  37. data/lib/active_model/serializer/adapter/attributes.rb +66 -0
  38. data/lib/active_model/serializer/adapter/base.rb +58 -0
  39. data/lib/active_model/serializer/adapter/cached_serializer.rb +45 -0
  40. data/lib/active_model/serializer/adapter/fragment_cache.rb +111 -0
  41. data/lib/active_model/serializer/adapter/json/fragment_cache.rb +13 -0
  42. data/lib/active_model/serializer/adapter/json.rb +21 -0
  43. data/lib/active_model/serializer/adapter/json_api/deserialization.rb +207 -0
  44. data/lib/active_model/serializer/adapter/json_api/fragment_cache.rb +21 -0
  45. data/lib/active_model/serializer/adapter/json_api/link.rb +44 -0
  46. data/lib/active_model/serializer/adapter/json_api/pagination_links.rb +58 -0
  47. data/lib/active_model/serializer/adapter/json_api.rb +223 -0
  48. data/lib/active_model/serializer/adapter/null.rb +11 -0
  49. data/lib/active_model/serializer/adapter.rb +91 -0
  50. data/lib/active_model/serializer/array_serializer.rb +9 -0
  51. data/lib/active_model/serializer/association.rb +20 -0
  52. data/lib/active_model/serializer/associations.rb +87 -220
  53. data/lib/active_model/serializer/attribute.rb +25 -0
  54. data/lib/active_model/serializer/attributes.rb +82 -0
  55. data/lib/active_model/serializer/belongs_to_reflection.rb +10 -0
  56. data/lib/active_model/serializer/caching.rb +100 -0
  57. data/lib/active_model/serializer/collection_reflection.rb +7 -0
  58. data/lib/active_model/serializer/collection_serializer.rb +47 -0
  59. data/lib/active_model/serializer/configuration.rb +28 -0
  60. data/lib/active_model/serializer/field.rb +56 -0
  61. data/lib/active_model/serializer/fieldset.rb +31 -0
  62. data/lib/active_model/serializer/has_many_reflection.rb +10 -0
  63. data/lib/active_model/serializer/has_one_reflection.rb +10 -0
  64. data/lib/active_model/serializer/include_tree.rb +111 -0
  65. data/lib/active_model/serializer/links.rb +33 -0
  66. data/lib/active_model/serializer/lint.rb +142 -0
  67. data/lib/active_model/serializer/reflection.rb +91 -0
  68. data/lib/active_model/serializer/singular_reflection.rb +7 -0
  69. data/lib/active_model/serializer/type.rb +25 -0
  70. data/lib/active_model/{serializers → serializer}/version.rb +1 -1
  71. data/lib/active_model/serializer.rb +99 -479
  72. data/lib/active_model_serializers/callbacks.rb +55 -0
  73. data/lib/active_model_serializers/deserialization.rb +13 -0
  74. data/lib/active_model_serializers/logging.rb +119 -0
  75. data/lib/active_model_serializers/model.rb +39 -0
  76. data/lib/active_model_serializers/railtie.rb +38 -0
  77. data/lib/active_model_serializers/serialization_context.rb +10 -0
  78. data/lib/active_model_serializers/test/schema.rb +103 -0
  79. data/lib/active_model_serializers/test/serializer.rb +125 -0
  80. data/lib/active_model_serializers/test.rb +7 -0
  81. data/lib/active_model_serializers.rb +20 -92
  82. data/lib/generators/rails/USAGE +6 -0
  83. data/lib/generators/rails/resource_override.rb +10 -0
  84. data/lib/generators/rails/serializer_generator.rb +36 -0
  85. data/lib/generators/rails/templates/serializer.rb.erb +8 -0
  86. data/lib/grape/active_model_serializers.rb +14 -0
  87. data/lib/grape/formatters/active_model_serializers.rb +15 -0
  88. data/lib/grape/helpers/active_model_serializers.rb +16 -0
  89. data/test/action_controller/adapter_selector_test.rb +53 -0
  90. data/test/action_controller/explicit_serializer_test.rb +134 -0
  91. data/test/action_controller/json/include_test.rb +167 -0
  92. data/test/action_controller/json_api/deserialization_test.rb +59 -0
  93. data/test/action_controller/json_api/linked_test.rb +196 -0
  94. data/test/action_controller/json_api/pagination_test.rb +116 -0
  95. data/test/{serialization_scope_name_test.rb → action_controller/serialization_scope_name_test.rb} +11 -15
  96. data/test/action_controller/serialization_test.rb +435 -0
  97. data/test/active_model_serializers/logging_test.rb +77 -0
  98. data/test/active_model_serializers/model_test.rb +9 -0
  99. data/test/active_model_serializers/railtie_test_isolated.rb +57 -0
  100. data/test/active_model_serializers/serialization_context_test.rb +18 -0
  101. data/test/active_model_serializers/test/schema_test.rb +128 -0
  102. data/test/active_model_serializers/test/serializer_test.rb +63 -0
  103. data/test/active_record_test.rb +9 -0
  104. data/test/adapter/fragment_cache_test.rb +38 -0
  105. data/test/adapter/json/belongs_to_test.rb +47 -0
  106. data/test/adapter/json/collection_test.rb +92 -0
  107. data/test/adapter/json/has_many_test.rb +47 -0
  108. data/test/adapter/json_api/belongs_to_test.rb +157 -0
  109. data/test/adapter/json_api/collection_test.rb +97 -0
  110. data/test/adapter/json_api/fields_test.rb +89 -0
  111. data/test/adapter/json_api/has_many_embed_ids_test.rb +45 -0
  112. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +98 -0
  113. data/test/adapter/json_api/has_many_test.rb +145 -0
  114. data/test/adapter/json_api/has_one_test.rb +81 -0
  115. data/test/adapter/json_api/json_api_test.rb +37 -0
  116. data/test/adapter/json_api/linked_test.rb +394 -0
  117. data/test/adapter/json_api/links_test.rb +68 -0
  118. data/test/adapter/json_api/pagination_links_test.rb +115 -0
  119. data/test/adapter/json_api/parse_test.rb +139 -0
  120. data/test/adapter/json_api/resource_type_config_test.rb +71 -0
  121. data/test/adapter/json_api/toplevel_jsonapi_test.rb +84 -0
  122. data/test/adapter/json_test.rb +47 -0
  123. data/test/adapter/null_test.rb +25 -0
  124. data/test/adapter_test.rb +42 -0
  125. data/test/array_serializer_test.rb +36 -73
  126. data/test/collection_serializer_test.rb +100 -0
  127. data/test/fixtures/active_record.rb +56 -0
  128. data/test/fixtures/poro.rb +229 -0
  129. data/test/generators/scaffold_controller_generator_test.rb +24 -0
  130. data/test/generators/serializer_generator_test.rb +57 -0
  131. data/test/grape_test.rb +82 -0
  132. data/test/include_tree/from_include_args_test.rb +26 -0
  133. data/test/include_tree/from_string_test.rb +94 -0
  134. data/test/include_tree/include_args_to_hash_test.rb +64 -0
  135. data/test/lint_test.rb +40 -0
  136. data/test/logger_test.rb +18 -0
  137. data/test/poro_test.rb +9 -0
  138. data/test/serializable_resource_test.rb +27 -0
  139. data/test/serializers/adapter_for_test.rb +166 -0
  140. data/test/serializers/association_macros_test.rb +36 -0
  141. data/test/serializers/associations_test.rb +267 -0
  142. data/test/serializers/attribute_test.rb +123 -0
  143. data/test/serializers/attributes_test.rb +52 -0
  144. data/test/serializers/cache_test.rb +209 -0
  145. data/test/serializers/configuration_test.rb +32 -0
  146. data/test/serializers/fieldset_test.rb +14 -0
  147. data/test/serializers/meta_test.rb +130 -0
  148. data/test/serializers/options_test.rb +21 -0
  149. data/test/serializers/root_test.rb +21 -0
  150. data/test/serializers/serializer_for_test.rb +134 -0
  151. data/test/support/custom_schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
  152. data/test/support/isolated_unit.rb +77 -0
  153. data/test/support/rails5_shims.rb +29 -0
  154. data/test/support/rails_app.rb +25 -0
  155. data/test/support/schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
  156. data/test/support/schemas/active_model_serializers/test/schema_test/my/show.json +6 -0
  157. data/test/support/schemas/custom/show.json +7 -0
  158. data/test/support/schemas/hyper_schema.json +93 -0
  159. data/test/support/schemas/render_using_json_api.json +43 -0
  160. data/test/support/schemas/simple_json_pointers.json +10 -0
  161. data/test/support/serialization_testing.rb +53 -0
  162. data/test/support/simplecov.rb +6 -0
  163. data/test/support/stream_capture.rb +50 -0
  164. data/test/support/test_case.rb +19 -0
  165. data/test/test_helper.rb +55 -24
  166. metadata +358 -42
  167. data/DESIGN.textile +0 -586
  168. data/Gemfile.edge +0 -9
  169. data/bench/perf.rb +0 -43
  170. data/cruft.md +0 -19
  171. data/lib/active_model/array_serializer.rb +0 -104
  172. data/lib/active_record/serializer_override.rb +0 -16
  173. data/lib/generators/resource_override.rb +0 -13
  174. data/lib/generators/serializer/USAGE +0 -9
  175. data/lib/generators/serializer/serializer_generator.rb +0 -42
  176. data/lib/generators/serializer/templates/serializer.rb +0 -19
  177. data/test/association_test.rb +0 -592
  178. data/test/caching_test.rb +0 -96
  179. data/test/generators_test.rb +0 -85
  180. data/test/no_serialization_scope_test.rb +0 -34
  181. data/test/serialization_test.rb +0 -392
  182. data/test/serializer_support_test.rb +0 -51
  183. data/test/serializer_test.rb +0 -1465
  184. data/test/test_fakes.rb +0 -217
@@ -0,0 +1,53 @@
1
+ require 'test_helper'
2
+
3
+ module ActionController
4
+ module Serialization
5
+ class AdapterSelectorTest < ActionController::TestCase
6
+ class AdapterSelectorTestController < ActionController::Base
7
+ def render_using_default_adapter
8
+ @profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
9
+ render json: @profile
10
+ end
11
+
12
+ def render_using_adapter_override
13
+ @profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
14
+ render json: @profile, adapter: :json_api
15
+ end
16
+
17
+ def render_skipping_adapter
18
+ @profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
19
+ render json: @profile, adapter: false
20
+ end
21
+ end
22
+
23
+ tests AdapterSelectorTestController
24
+
25
+ def test_render_using_default_adapter
26
+ get :render_using_default_adapter
27
+ assert_equal '{"name":"Name 1","description":"Description 1"}', response.body
28
+ end
29
+
30
+ def test_render_using_adapter_override
31
+ get :render_using_adapter_override
32
+
33
+ expected = {
34
+ data: {
35
+ id: assigns(:profile).id.to_s,
36
+ type: 'profiles',
37
+ attributes: {
38
+ name: 'Name 1',
39
+ description: 'Description 1',
40
+ }
41
+ }
42
+ }
43
+
44
+ assert_equal expected.to_json, response.body
45
+ end
46
+
47
+ def test_render_skipping_adapter
48
+ get :render_skipping_adapter
49
+ assert_equal '{"name":"Name 1","description":"Description 1","comments":"Comments 1"}', response.body
50
+ end
51
+ end
52
+ end
53
+ end
@@ -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,59 @@
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
+ end
13
+
14
+ tests DeserializationTestController
15
+
16
+ def test_deserialization
17
+ hash = {
18
+ 'data' => {
19
+ 'type' => 'photos',
20
+ 'id' => 'zorglub',
21
+ 'attributes' => {
22
+ 'title' => 'Ember Hamster',
23
+ 'src' => 'http://example.com/images/productivity.png'
24
+ },
25
+ 'relationships' => {
26
+ 'author' => {
27
+ 'data' => nil
28
+ },
29
+ 'photographer' => {
30
+ 'data' => { 'type' => 'people', 'id' => '9' }
31
+ },
32
+ 'comments' => {
33
+ 'data' => [
34
+ { 'type' => 'comments', 'id' => '1' },
35
+ { 'type' => 'comments', 'id' => '2' }
36
+ ]
37
+ }
38
+ }
39
+ }
40
+ }
41
+
42
+ post :render_parsed_payload, hash
43
+
44
+ response = JSON.parse(@response.body)
45
+ expected = {
46
+ 'id' => 'zorglub',
47
+ 'title' => 'Ember Hamster',
48
+ 'src' => 'http://example.com/images/productivity.png',
49
+ 'author_id' => nil,
50
+ 'photographer_id' => '9',
51
+ 'comment_ids' => %w(1 2)
52
+ }
53
+
54
+ assert_equal(expected, response)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,196 @@
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
+ def setup_post
9
+ ActionController::Base.cache_store.clear
10
+ @role1 = Role.new(id: 1, name: 'admin')
11
+ @role2 = Role.new(id: 2, name: 'colab')
12
+ @author = Author.new(id: 1, name: 'Steve K.')
13
+ @author.posts = []
14
+ @author.bio = nil
15
+ @author.roles = [@role1, @role2]
16
+ @role1.author = @author
17
+ @role2.author = @author
18
+ @author2 = Author.new(id: 2, name: 'Anonymous')
19
+ @author2.posts = []
20
+ @author2.bio = nil
21
+ @author2.roles = []
22
+ @post = Post.new(id: 1, title: 'New Post', body: 'Body')
23
+ @first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
24
+ @second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
25
+ @post.comments = [@first_comment, @second_comment]
26
+ @post.author = @author
27
+ @first_comment.post = @post
28
+ @first_comment.author = @author2
29
+ @second_comment.post = @post
30
+ @second_comment.author = nil
31
+ @post2 = Post.new(id: 2, title: 'Another Post', body: 'Body')
32
+ @post2.author = @author
33
+ @post2.comments = []
34
+ @blog = Blog.new(id: 1, name: 'My Blog!!')
35
+ @post.blog = @blog
36
+ @post2.blog = @blog
37
+ end
38
+
39
+ def render_resource_without_include
40
+ setup_post
41
+ render json: @post, adapter: :json_api
42
+ end
43
+
44
+ def render_resource_with_include
45
+ setup_post
46
+ render json: @post, include: [:author], adapter: :json_api
47
+ end
48
+
49
+ def render_resource_with_include_of_custom_key_by_original
50
+ setup_post
51
+ render json: @post, include: [:reviews], adapter: :json_api, serializer: PostWithCustomKeysSerializer
52
+ end
53
+
54
+ def render_resource_with_nested_include
55
+ setup_post
56
+ render json: @post, include: [comments: [:author]], adapter: :json_api
57
+ end
58
+
59
+ def render_resource_with_nested_has_many_include_wildcard
60
+ setup_post
61
+ render json: @post, include: 'author.*', adapter: :json_api
62
+ end
63
+
64
+ def render_resource_with_missing_nested_has_many_include
65
+ setup_post
66
+ @post.author = @author2 # author2 has no roles.
67
+ render json: @post, include: [author: [:roles]], adapter: :json_api
68
+ end
69
+
70
+ def render_collection_with_missing_nested_has_many_include
71
+ setup_post
72
+ @post.author = @author2
73
+ render json: [@post, @post2], include: [author: [:roles]], adapter: :json_api
74
+ end
75
+
76
+ def render_collection_without_include
77
+ setup_post
78
+ render json: [@post], adapter: :json_api
79
+ end
80
+
81
+ def render_collection_with_include
82
+ setup_post
83
+ render json: [@post], include: 'author, comments', adapter: :json_api
84
+ end
85
+ end
86
+
87
+ tests LinkedTestController
88
+
89
+ def test_render_resource_without_include
90
+ get :render_resource_without_include
91
+ response = JSON.parse(@response.body)
92
+ refute response.key? 'included'
93
+ end
94
+
95
+ def test_render_resource_with_include
96
+ get :render_resource_with_include
97
+ response = JSON.parse(@response.body)
98
+ assert response.key? 'included'
99
+ assert_equal 1, response['included'].size
100
+ assert_equal 'Steve K.', response['included'].first['attributes']['name']
101
+ end
102
+
103
+ def test_render_resource_with_nested_has_many_include
104
+ get :render_resource_with_nested_has_many_include_wildcard
105
+ response = JSON.parse(@response.body)
106
+ expected_linked = [
107
+ {
108
+ 'id' => '1',
109
+ 'type' => 'authors',
110
+ 'attributes' => {
111
+ 'name' => 'Steve K.'
112
+ },
113
+ 'relationships' => {
114
+ 'posts' => { 'data' => [] },
115
+ 'roles' => { 'data' => [{ 'type' => 'roles', 'id' => '1' }, { 'type' => 'roles', 'id' => '2' }] },
116
+ 'bio' => { 'data' => nil }
117
+ }
118
+ }, {
119
+ 'id' => '1',
120
+ 'type' => 'roles',
121
+ 'attributes' => {
122
+ 'name' => 'admin',
123
+ 'description' => nil,
124
+ 'slug' => 'admin-1'
125
+ },
126
+ 'relationships' => {
127
+ 'author' => { 'data' => { 'type' => 'authors', 'id' => '1' } }
128
+ }
129
+ }, {
130
+ 'id' => '2',
131
+ 'type' => 'roles',
132
+ 'attributes' => {
133
+ 'name' => 'colab',
134
+ 'description' => nil,
135
+ 'slug' => 'colab-2'
136
+ },
137
+ 'relationships' => {
138
+ 'author' => { 'data' => { 'type' => 'authors', 'id' => '1' } }
139
+ }
140
+ }
141
+ ]
142
+ assert_equal expected_linked, response['included']
143
+ end
144
+
145
+ def test_render_resource_with_include_of_custom_key_by_original
146
+ get :render_resource_with_include_of_custom_key_by_original
147
+ response = JSON.parse(@response.body)
148
+ assert response.key? 'included'
149
+
150
+ relationships = response['data']['relationships']
151
+
152
+ assert_includes relationships, 'reviews'
153
+ assert_includes relationships, 'writer'
154
+ assert_includes relationships, 'site'
155
+ end
156
+
157
+ def test_render_resource_with_nested_include
158
+ get :render_resource_with_nested_include
159
+ response = JSON.parse(@response.body)
160
+ assert response.key? 'included'
161
+ assert_equal 3, response['included'].size
162
+ end
163
+
164
+ def test_render_collection_without_include
165
+ get :render_collection_without_include
166
+ response = JSON.parse(@response.body)
167
+ refute response.key? 'included'
168
+ end
169
+
170
+ def test_render_collection_with_include
171
+ get :render_collection_with_include
172
+ response = JSON.parse(@response.body)
173
+ assert response.key? 'included'
174
+ end
175
+
176
+ def test_render_resource_with_nested_attributes_even_when_missing_associations
177
+ get :render_resource_with_missing_nested_has_many_include
178
+ response = JSON.parse(@response.body)
179
+ assert response.key? 'included'
180
+ refute has_type?(response['included'], 'roles')
181
+ end
182
+
183
+ def test_render_collection_with_missing_nested_has_many_include
184
+ get :render_collection_with_missing_nested_has_many_include
185
+ response = JSON.parse(@response.body)
186
+ assert response.key? 'included'
187
+ assert has_type?(response['included'], 'roles')
188
+ end
189
+
190
+ def has_type?(collection, value)
191
+ collection.detect { |i| i['type'] == value }
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end