active_model_serializers_custom 0.10.90

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 (215) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE.md +29 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +15 -0
  4. data/.gitignore +35 -0
  5. data/.rubocop.yml +109 -0
  6. data/.simplecov +110 -0
  7. data/.travis.yml +63 -0
  8. data/CHANGELOG.md +727 -0
  9. data/CODE_OF_CONDUCT.md +74 -0
  10. data/CONTRIBUTING.md +105 -0
  11. data/Gemfile +74 -0
  12. data/MIT-LICENSE +22 -0
  13. data/README.md +305 -0
  14. data/Rakefile +76 -0
  15. data/active_model_serializers.gemspec +64 -0
  16. data/appveyor.yml +28 -0
  17. data/bin/bench +171 -0
  18. data/bin/bench_regression +316 -0
  19. data/bin/rubocop +38 -0
  20. data/bin/serve_benchmark +39 -0
  21. data/docs/README.md +41 -0
  22. data/docs/STYLE.md +58 -0
  23. data/docs/general/adapters.md +269 -0
  24. data/docs/general/caching.md +58 -0
  25. data/docs/general/configuration_options.md +185 -0
  26. data/docs/general/deserialization.md +100 -0
  27. data/docs/general/fields.md +31 -0
  28. data/docs/general/getting_started.md +133 -0
  29. data/docs/general/instrumentation.md +40 -0
  30. data/docs/general/key_transforms.md +40 -0
  31. data/docs/general/logging.md +21 -0
  32. data/docs/general/rendering.md +293 -0
  33. data/docs/general/serializers.md +495 -0
  34. data/docs/how-open-source-maintained.jpg +0 -0
  35. data/docs/howto/add_pagination_links.md +138 -0
  36. data/docs/howto/add_relationship_links.md +140 -0
  37. data/docs/howto/add_root_key.md +62 -0
  38. data/docs/howto/grape_integration.md +42 -0
  39. data/docs/howto/outside_controller_use.md +66 -0
  40. data/docs/howto/passing_arbitrary_options.md +27 -0
  41. data/docs/howto/serialize_poro.md +73 -0
  42. data/docs/howto/test.md +154 -0
  43. data/docs/howto/upgrade_from_0_8_to_0_10.md +265 -0
  44. data/docs/integrations/ember-and-json-api.md +147 -0
  45. data/docs/integrations/grape.md +19 -0
  46. data/docs/jsonapi/errors.md +56 -0
  47. data/docs/jsonapi/schema.md +151 -0
  48. data/docs/jsonapi/schema/schema.json +366 -0
  49. data/docs/rfcs/0000-namespace.md +106 -0
  50. data/docs/rfcs/template.md +15 -0
  51. data/lib/action_controller/serialization.rb +76 -0
  52. data/lib/active_model/serializable_resource.rb +13 -0
  53. data/lib/active_model/serializer.rb +418 -0
  54. data/lib/active_model/serializer/adapter.rb +26 -0
  55. data/lib/active_model/serializer/adapter/attributes.rb +17 -0
  56. data/lib/active_model/serializer/adapter/base.rb +20 -0
  57. data/lib/active_model/serializer/adapter/json.rb +17 -0
  58. data/lib/active_model/serializer/adapter/json_api.rb +17 -0
  59. data/lib/active_model/serializer/adapter/null.rb +17 -0
  60. data/lib/active_model/serializer/array_serializer.rb +14 -0
  61. data/lib/active_model/serializer/association.rb +91 -0
  62. data/lib/active_model/serializer/attribute.rb +27 -0
  63. data/lib/active_model/serializer/belongs_to_reflection.rb +13 -0
  64. data/lib/active_model/serializer/collection_serializer.rb +90 -0
  65. data/lib/active_model/serializer/concerns/caching.rb +304 -0
  66. data/lib/active_model/serializer/error_serializer.rb +16 -0
  67. data/lib/active_model/serializer/errors_serializer.rb +34 -0
  68. data/lib/active_model/serializer/field.rb +92 -0
  69. data/lib/active_model/serializer/fieldset.rb +33 -0
  70. data/lib/active_model/serializer/has_many_reflection.rb +12 -0
  71. data/lib/active_model/serializer/has_one_reflection.rb +9 -0
  72. data/lib/active_model/serializer/lazy_association.rb +99 -0
  73. data/lib/active_model/serializer/link.rb +23 -0
  74. data/lib/active_model/serializer/lint.rb +152 -0
  75. data/lib/active_model/serializer/null.rb +19 -0
  76. data/lib/active_model/serializer/reflection.rb +212 -0
  77. data/lib/active_model/serializer/version.rb +7 -0
  78. data/lib/active_model_serializers.rb +63 -0
  79. data/lib/active_model_serializers/adapter.rb +100 -0
  80. data/lib/active_model_serializers/adapter/attributes.rb +15 -0
  81. data/lib/active_model_serializers/adapter/base.rb +85 -0
  82. data/lib/active_model_serializers/adapter/json.rb +23 -0
  83. data/lib/active_model_serializers/adapter/json_api.rb +535 -0
  84. data/lib/active_model_serializers/adapter/json_api/deserialization.rb +215 -0
  85. data/lib/active_model_serializers/adapter/json_api/error.rb +98 -0
  86. data/lib/active_model_serializers/adapter/json_api/jsonapi.rb +51 -0
  87. data/lib/active_model_serializers/adapter/json_api/link.rb +85 -0
  88. data/lib/active_model_serializers/adapter/json_api/meta.rb +39 -0
  89. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +90 -0
  90. data/lib/active_model_serializers/adapter/json_api/relationship.rb +106 -0
  91. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +68 -0
  92. data/lib/active_model_serializers/adapter/null.rb +11 -0
  93. data/lib/active_model_serializers/callbacks.rb +57 -0
  94. data/lib/active_model_serializers/deprecate.rb +56 -0
  95. data/lib/active_model_serializers/deserialization.rb +17 -0
  96. data/lib/active_model_serializers/json_pointer.rb +16 -0
  97. data/lib/active_model_serializers/logging.rb +124 -0
  98. data/lib/active_model_serializers/lookup_chain.rb +82 -0
  99. data/lib/active_model_serializers/model.rb +132 -0
  100. data/lib/active_model_serializers/railtie.rb +52 -0
  101. data/lib/active_model_serializers/register_jsonapi_renderer.rb +80 -0
  102. data/lib/active_model_serializers/serializable_resource.rb +84 -0
  103. data/lib/active_model_serializers/serialization_context.rb +41 -0
  104. data/lib/active_model_serializers/test.rb +9 -0
  105. data/lib/active_model_serializers/test/schema.rb +140 -0
  106. data/lib/active_model_serializers/test/serializer.rb +127 -0
  107. data/lib/generators/rails/USAGE +6 -0
  108. data/lib/generators/rails/resource_override.rb +12 -0
  109. data/lib/generators/rails/serializer_generator.rb +38 -0
  110. data/lib/generators/rails/templates/serializer.rb.erb +8 -0
  111. data/lib/grape/active_model_serializers.rb +18 -0
  112. data/lib/grape/formatters/active_model_serializers.rb +34 -0
  113. data/lib/grape/helpers/active_model_serializers.rb +19 -0
  114. data/lib/tasks/rubocop.rake +55 -0
  115. data/test/action_controller/adapter_selector_test.rb +64 -0
  116. data/test/action_controller/explicit_serializer_test.rb +137 -0
  117. data/test/action_controller/json/include_test.rb +248 -0
  118. data/test/action_controller/json_api/deserialization_test.rb +114 -0
  119. data/test/action_controller/json_api/errors_test.rb +42 -0
  120. data/test/action_controller/json_api/fields_test.rb +68 -0
  121. data/test/action_controller/json_api/linked_test.rb +204 -0
  122. data/test/action_controller/json_api/pagination_test.rb +126 -0
  123. data/test/action_controller/json_api/transform_test.rb +191 -0
  124. data/test/action_controller/lookup_proc_test.rb +51 -0
  125. data/test/action_controller/namespace_lookup_test.rb +239 -0
  126. data/test/action_controller/serialization_scope_name_test.rb +237 -0
  127. data/test/action_controller/serialization_test.rb +480 -0
  128. data/test/active_model_serializers/adapter_for_test.rb +210 -0
  129. data/test/active_model_serializers/json_pointer_test.rb +24 -0
  130. data/test/active_model_serializers/logging_test.rb +79 -0
  131. data/test/active_model_serializers/model_test.rb +144 -0
  132. data/test/active_model_serializers/railtie_test_isolated.rb +70 -0
  133. data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +163 -0
  134. data/test/active_model_serializers/serialization_context_test_isolated.rb +73 -0
  135. data/test/active_model_serializers/test/schema_test.rb +133 -0
  136. data/test/active_model_serializers/test/serializer_test.rb +64 -0
  137. data/test/active_record_test.rb +11 -0
  138. data/test/adapter/attributes_test.rb +42 -0
  139. data/test/adapter/deprecation_test.rb +102 -0
  140. data/test/adapter/json/belongs_to_test.rb +47 -0
  141. data/test/adapter/json/collection_test.rb +106 -0
  142. data/test/adapter/json/has_many_test.rb +55 -0
  143. data/test/adapter/json/transform_test.rb +95 -0
  144. data/test/adapter/json_api/belongs_to_test.rb +157 -0
  145. data/test/adapter/json_api/collection_test.rb +98 -0
  146. data/test/adapter/json_api/errors_test.rb +78 -0
  147. data/test/adapter/json_api/fields_test.rb +98 -0
  148. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +98 -0
  149. data/test/adapter/json_api/has_many_test.rb +175 -0
  150. data/test/adapter/json_api/has_one_test.rb +82 -0
  151. data/test/adapter/json_api/include_data_if_sideloaded_test.rb +215 -0
  152. data/test/adapter/json_api/json_api_test.rb +35 -0
  153. data/test/adapter/json_api/linked_test.rb +415 -0
  154. data/test/adapter/json_api/links_test.rb +112 -0
  155. data/test/adapter/json_api/pagination_links_test.rb +208 -0
  156. data/test/adapter/json_api/parse_test.rb +139 -0
  157. data/test/adapter/json_api/relationship_test.rb +399 -0
  158. data/test/adapter/json_api/resource_meta_test.rb +102 -0
  159. data/test/adapter/json_api/toplevel_jsonapi_test.rb +84 -0
  160. data/test/adapter/json_api/transform_test.rb +514 -0
  161. data/test/adapter/json_api/type_test.rb +195 -0
  162. data/test/adapter/json_test.rb +48 -0
  163. data/test/adapter/null_test.rb +24 -0
  164. data/test/adapter/polymorphic_test.rb +220 -0
  165. data/test/adapter_test.rb +69 -0
  166. data/test/array_serializer_test.rb +24 -0
  167. data/test/benchmark/app.rb +67 -0
  168. data/test/benchmark/benchmarking_support.rb +69 -0
  169. data/test/benchmark/bm_active_record.rb +83 -0
  170. data/test/benchmark/bm_adapter.rb +40 -0
  171. data/test/benchmark/bm_caching.rb +121 -0
  172. data/test/benchmark/bm_lookup_chain.rb +85 -0
  173. data/test/benchmark/bm_transform.rb +47 -0
  174. data/test/benchmark/config.ru +3 -0
  175. data/test/benchmark/controllers.rb +85 -0
  176. data/test/benchmark/fixtures.rb +221 -0
  177. data/test/cache_test.rb +717 -0
  178. data/test/collection_serializer_test.rb +129 -0
  179. data/test/fixtures/active_record.rb +115 -0
  180. data/test/fixtures/poro.rb +227 -0
  181. data/test/generators/scaffold_controller_generator_test.rb +26 -0
  182. data/test/generators/serializer_generator_test.rb +77 -0
  183. data/test/grape_test.rb +198 -0
  184. data/test/lint_test.rb +51 -0
  185. data/test/logger_test.rb +22 -0
  186. data/test/poro_test.rb +11 -0
  187. data/test/serializable_resource_test.rb +81 -0
  188. data/test/serializers/association_macros_test.rb +39 -0
  189. data/test/serializers/associations_test.rb +520 -0
  190. data/test/serializers/attribute_test.rb +155 -0
  191. data/test/serializers/attributes_test.rb +54 -0
  192. data/test/serializers/caching_configuration_test_isolated.rb +172 -0
  193. data/test/serializers/configuration_test.rb +34 -0
  194. data/test/serializers/fieldset_test.rb +16 -0
  195. data/test/serializers/meta_test.rb +204 -0
  196. data/test/serializers/options_test.rb +34 -0
  197. data/test/serializers/read_attribute_for_serialization_test.rb +81 -0
  198. data/test/serializers/reflection_test.rb +481 -0
  199. data/test/serializers/root_test.rb +23 -0
  200. data/test/serializers/serialization_test.rb +57 -0
  201. data/test/serializers/serializer_for_test.rb +138 -0
  202. data/test/serializers/serializer_for_with_namespace_test.rb +90 -0
  203. data/test/support/custom_schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
  204. data/test/support/isolated_unit.rb +86 -0
  205. data/test/support/rails5_shims.rb +55 -0
  206. data/test/support/rails_app.rb +40 -0
  207. data/test/support/schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
  208. data/test/support/schemas/active_model_serializers/test/schema_test/my/show.json +6 -0
  209. data/test/support/schemas/custom/show.json +7 -0
  210. data/test/support/schemas/hyper_schema.json +93 -0
  211. data/test/support/schemas/render_using_json_api.json +43 -0
  212. data/test/support/schemas/simple_json_pointers.json +10 -0
  213. data/test/support/serialization_testing.rb +81 -0
  214. data/test/test_helper.rb +72 -0
  215. metadata +622 -0
@@ -0,0 +1,208 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+ require 'will_paginate/array'
5
+ require 'kaminari'
6
+ require 'kaminari/hooks'
7
+ ::Kaminari::Hooks.init
8
+
9
+ module ActiveModelSerializers
10
+ module Adapter
11
+ class JsonApi
12
+ class PaginationLinksTest < ActiveSupport::TestCase
13
+ URI = 'http://example.com'.freeze
14
+
15
+ def setup
16
+ ActionController::Base.cache_store.clear
17
+ @array = [
18
+ Profile.new(id: 1, name: 'Name 1', description: 'Description 1', comments: 'Comments 1'),
19
+ Profile.new(id: 2, name: 'Name 2', description: 'Description 2', comments: 'Comments 2'),
20
+ Profile.new(id: 3, name: 'Name 3', description: 'Description 3', comments: 'Comments 3'),
21
+ Profile.new(id: 4, name: 'Name 4', description: 'Description 4', comments: 'Comments 4'),
22
+ Profile.new(id: 5, name: 'Name 5', description: 'Description 5', comments: 'Comments 5')
23
+ ]
24
+ end
25
+
26
+ def mock_request(query_parameters = {}, original_url = URI)
27
+ context = Minitest::Mock.new
28
+ context.expect(:request_url, original_url)
29
+ context.expect(:query_parameters, query_parameters)
30
+ context.expect(:key_transform, nil)
31
+ end
32
+
33
+ def load_adapter(paginated_collection, mock_request = nil)
34
+ render_options = { adapter: :json_api }
35
+ render_options[:serialization_context] = mock_request if mock_request
36
+ serializable(paginated_collection, render_options)
37
+ end
38
+
39
+ def using_kaminari(page = 2)
40
+ Kaminari.paginate_array(@array).page(page).per(2)
41
+ end
42
+
43
+ def using_will_paginate(page = 2)
44
+ @array.paginate(page: page, per_page: 2)
45
+ end
46
+
47
+ def data
48
+ {
49
+ data: [
50
+ { id: '1', type: 'profiles', attributes: { name: 'Name 1', description: 'Description 1' } },
51
+ { id: '2', type: 'profiles', attributes: { name: 'Name 2', description: 'Description 2' } },
52
+ { id: '3', type: 'profiles', attributes: { name: 'Name 3', description: 'Description 3' } },
53
+ { id: '4', type: 'profiles', attributes: { name: 'Name 4', description: 'Description 4' } },
54
+ { id: '5', type: 'profiles', attributes: { name: 'Name 5', description: 'Description 5' } }
55
+ ]
56
+ }
57
+ end
58
+
59
+ def empty_collection_links
60
+ {
61
+ self: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
62
+ first: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
63
+ prev: nil,
64
+ next: nil,
65
+ last: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2"
66
+ }
67
+ end
68
+
69
+ def links
70
+ {
71
+ links: {
72
+ self: "#{URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2",
73
+ first: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
74
+ prev: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
75
+ next: "#{URI}?page%5Bnumber%5D=3&page%5Bsize%5D=2",
76
+ last: "#{URI}?page%5Bnumber%5D=3&page%5Bsize%5D=2"
77
+ }
78
+ }
79
+ end
80
+
81
+ def last_page_links
82
+ {
83
+ links: {
84
+ self: "#{URI}?page%5Bnumber%5D=3&page%5Bsize%5D=2",
85
+ first: "#{URI}?page%5Bnumber%5D=1&page%5Bsize%5D=2",
86
+ prev: "#{URI}?page%5Bnumber%5D=2&page%5Bsize%5D=2",
87
+ next: nil,
88
+ last: "#{URI}?page%5Bnumber%5D=3&page%5Bsize%5D=2"
89
+ }
90
+ }
91
+ end
92
+
93
+ def expected_response_when_unpaginatable
94
+ data
95
+ end
96
+
97
+ def expected_response_with_pagination_links
98
+ {}.tap do |hash|
99
+ hash[:data] = data.values.flatten[2..3]
100
+ hash.merge! links
101
+ end
102
+ end
103
+
104
+ def expected_response_without_pagination_links
105
+ {}.tap do |hash|
106
+ hash[:data] = data.values.flatten[2..3]
107
+ end
108
+ end
109
+
110
+ def expected_response_with_pagination_links_and_additional_params
111
+ new_links = links[:links].each_with_object({}) { |(key, value), hash| hash[key] = "#{value}&test=test" }
112
+ {}.tap do |hash|
113
+ hash[:data] = data.values.flatten[2..3]
114
+ hash.merge! links: new_links
115
+ end
116
+ end
117
+
118
+ def expected_response_with_last_page_pagination_links
119
+ {}.tap do |hash|
120
+ hash[:data] = [data.values.flatten.last]
121
+ hash.merge! last_page_links
122
+ end
123
+ end
124
+
125
+ def expected_response_with_empty_collection_pagination_links
126
+ {}.tap do |hash|
127
+ hash[:data] = []
128
+ hash.merge! links: empty_collection_links
129
+ end
130
+ end
131
+
132
+ def test_pagination_links_using_kaminari
133
+ adapter = load_adapter(using_kaminari, mock_request)
134
+
135
+ assert_equal expected_response_with_pagination_links, adapter.serializable_hash
136
+ end
137
+
138
+ def test_pagination_links_using_will_paginate
139
+ adapter = load_adapter(using_will_paginate, mock_request)
140
+
141
+ assert_equal expected_response_with_pagination_links, adapter.serializable_hash
142
+ end
143
+
144
+ def test_pagination_links_with_additional_params
145
+ adapter = load_adapter(using_will_paginate, mock_request(test: 'test'))
146
+
147
+ assert_equal expected_response_with_pagination_links_and_additional_params,
148
+ adapter.serializable_hash
149
+ end
150
+
151
+ def test_pagination_links_when_zero_results_kaminari
152
+ @array = []
153
+
154
+ adapter = load_adapter(using_kaminari(1), mock_request)
155
+
156
+ assert_equal expected_response_with_empty_collection_pagination_links, adapter.serializable_hash
157
+ end
158
+
159
+ def test_pagination_links_when_zero_results_will_paginate
160
+ @array = []
161
+
162
+ adapter = load_adapter(using_will_paginate(1), mock_request)
163
+
164
+ assert_equal expected_response_with_empty_collection_pagination_links, adapter.serializable_hash
165
+ end
166
+
167
+ def test_last_page_pagination_links_using_kaminari
168
+ adapter = load_adapter(using_kaminari(3), mock_request)
169
+
170
+ assert_equal expected_response_with_last_page_pagination_links, adapter.serializable_hash
171
+ end
172
+
173
+ def test_last_page_pagination_links_using_will_paginate
174
+ adapter = load_adapter(using_will_paginate(3), mock_request)
175
+
176
+ assert_equal expected_response_with_last_page_pagination_links, adapter.serializable_hash
177
+ end
178
+
179
+ def test_not_showing_pagination_links
180
+ adapter = load_adapter(@array, mock_request)
181
+
182
+ assert_equal expected_response_when_unpaginatable, adapter.serializable_hash
183
+ end
184
+
185
+ def test_raises_descriptive_error_when_serialization_context_unset
186
+ render_options = { adapter: :json_api }
187
+ adapter = serializable(using_kaminari, render_options)
188
+ exception_class = ActiveModelSerializers::Adapter::JsonApi::PaginationLinks::MissingSerializationContextError
189
+
190
+ exception = assert_raises(exception_class) do
191
+ adapter.as_json
192
+ end
193
+ assert_equal exception_class, exception.class
194
+ assert_match(/CollectionSerializer#paginated\?/, exception.message)
195
+ end
196
+
197
+ def test_pagination_links_not_present_when_disabled
198
+ ActiveModel::Serializer.config.jsonapi_pagination_links_enabled = false
199
+ adapter = load_adapter(using_kaminari, mock_request)
200
+
201
+ assert_equal expected_response_without_pagination_links, adapter.serializable_hash
202
+ ensure
203
+ ActiveModel::Serializer.config.jsonapi_pagination_links_enabled = true
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+ module ActiveModelSerializers
5
+ module Adapter
6
+ class JsonApi
7
+ module Deserialization
8
+ class ParseTest < Minitest::Test
9
+ def setup
10
+ @hash = {
11
+ 'data' => {
12
+ 'type' => 'photos',
13
+ 'id' => 'zorglub',
14
+ 'attributes' => {
15
+ 'title' => 'Ember Hamster',
16
+ 'src' => 'http://example.com/images/productivity.png'
17
+ },
18
+ 'relationships' => {
19
+ 'author' => {
20
+ 'data' => nil
21
+ },
22
+ 'photographer' => {
23
+ 'data' => { 'type' => 'people', 'id' => '9' }
24
+ },
25
+ 'comments' => {
26
+ 'data' => [
27
+ { 'type' => 'comments', 'id' => '1' },
28
+ { 'type' => 'comments', 'id' => '2' }
29
+ ]
30
+ }
31
+ }
32
+ }
33
+ }
34
+ @params = ActionController::Parameters.new(@hash)
35
+ @expected = {
36
+ id: 'zorglub',
37
+ title: 'Ember Hamster',
38
+ src: 'http://example.com/images/productivity.png',
39
+ author_id: nil,
40
+ photographer_id: '9',
41
+ comment_ids: %w(1 2)
42
+ }
43
+
44
+ @illformed_payloads = [nil,
45
+ {},
46
+ {
47
+ 'data' => nil
48
+ }, {
49
+ 'data' => { 'attributes' => [] }
50
+ }, {
51
+ 'data' => { 'relationships' => [] }
52
+ }, {
53
+ 'data' => {
54
+ 'relationships' => { 'rel' => nil }
55
+ }
56
+ }, {
57
+ 'data' => {
58
+ 'relationships' => { 'rel' => {} }
59
+ }
60
+ }]
61
+ end
62
+
63
+ def test_hash
64
+ parsed_hash = ActiveModelSerializers::Adapter::JsonApi::Deserialization.parse!(@hash)
65
+ assert_equal(@expected, parsed_hash)
66
+ end
67
+
68
+ def test_actioncontroller_parameters
69
+ assert_equal(false, @params.permitted?)
70
+ parsed_hash = ActiveModelSerializers::Adapter::JsonApi::Deserialization.parse!(@params)
71
+ assert_equal(@expected, parsed_hash)
72
+ end
73
+
74
+ def test_illformed_payloads_safe
75
+ @illformed_payloads.each do |p|
76
+ parsed_hash = ActiveModelSerializers::Adapter::JsonApi::Deserialization.parse(p)
77
+ assert_equal({}, parsed_hash)
78
+ end
79
+ end
80
+
81
+ def test_illformed_payloads_unsafe
82
+ @illformed_payloads.each do |p|
83
+ assert_raises(InvalidDocument) do
84
+ ActiveModelSerializers::Adapter::JsonApi::Deserialization.parse!(p)
85
+ end
86
+ end
87
+ end
88
+
89
+ def test_filter_fields_only
90
+ parsed_hash = ActiveModelSerializers::Adapter::JsonApi::Deserialization.parse!(@hash, only: [:id, :title, :author])
91
+ expected = {
92
+ id: 'zorglub',
93
+ title: 'Ember Hamster',
94
+ author_id: nil
95
+ }
96
+ assert_equal(expected, parsed_hash)
97
+ end
98
+
99
+ def test_filter_fields_except
100
+ parsed_hash = ActiveModelSerializers::Adapter::JsonApi::Deserialization.parse!(@hash, except: [:id, :title, :author])
101
+ expected = {
102
+ src: 'http://example.com/images/productivity.png',
103
+ photographer_id: '9',
104
+ comment_ids: %w(1 2)
105
+ }
106
+ assert_equal(expected, parsed_hash)
107
+ end
108
+
109
+ def test_keys
110
+ parsed_hash = ActiveModelSerializers::Adapter::JsonApi::Deserialization.parse!(@hash, keys: { author: :user, title: :post_title })
111
+ expected = {
112
+ id: 'zorglub',
113
+ post_title: 'Ember Hamster',
114
+ src: 'http://example.com/images/productivity.png',
115
+ user_id: nil,
116
+ photographer_id: '9',
117
+ comment_ids: %w(1 2)
118
+ }
119
+ assert_equal(expected, parsed_hash)
120
+ end
121
+
122
+ def test_polymorphic
123
+ parsed_hash = ActiveModelSerializers::Adapter::JsonApi::Deserialization.parse!(@hash, polymorphic: [:photographer])
124
+ expected = {
125
+ id: 'zorglub',
126
+ title: 'Ember Hamster',
127
+ src: 'http://example.com/images/productivity.png',
128
+ author_id: nil,
129
+ photographer_id: '9',
130
+ photographer_type: 'Person',
131
+ comment_ids: %w(1 2)
132
+ }
133
+ assert_equal(expected, parsed_hash)
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,399 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ module ActiveModelSerializers
6
+ module Adapter
7
+ class JsonApi
8
+ class RelationshipTest < ActiveSupport::TestCase
9
+ def test_relationship_with_data
10
+ expected = {
11
+ data: {
12
+ id: '1',
13
+ type: 'blogs'
14
+ }
15
+ }
16
+
17
+ model_attributes = { blog: Blog.new(id: 1) }
18
+ relationship_name = :blog
19
+ model = new_model(model_attributes)
20
+ actual = build_serializer_and_serialize_relationship(model, relationship_name) do
21
+ has_one :blog
22
+ end
23
+ assert_equal(expected, actual)
24
+ end
25
+
26
+ def test_relationship_with_nil_model
27
+ expected = { data: nil }
28
+
29
+ model_attributes = { blog: nil }
30
+ relationship_name = :blog
31
+ model = new_model(model_attributes)
32
+ actual = build_serializer_and_serialize_relationship(model, relationship_name) do
33
+ has_one :blog
34
+ end
35
+ assert_equal(expected, actual)
36
+ end
37
+
38
+ def test_relationship_with_data_array
39
+ expected = {
40
+ data: [
41
+ {
42
+ id: '1',
43
+ type: 'posts'
44
+ },
45
+ {
46
+ id: '2',
47
+ type: 'posts'
48
+ }
49
+ ]
50
+ }
51
+
52
+ model_attributes = { posts: [Post.new(id: 1), Post.new(id: 2)] }
53
+ relationship_name = :posts
54
+ model = new_model(model_attributes)
55
+ actual = build_serializer_and_serialize_relationship(model, relationship_name) do
56
+ has_many :posts
57
+ end
58
+ assert_equal(expected, actual)
59
+ end
60
+
61
+ def test_relationship_data_not_included
62
+ expected = { meta: {} }
63
+
64
+ model_attributes = { blog: :does_not_matter }
65
+ relationship_name = :blog
66
+ model = new_model(model_attributes)
67
+ actual = build_serializer_and_serialize_relationship(model, relationship_name) do
68
+ has_one :blog do
69
+ include_data false
70
+ end
71
+ end
72
+ assert_equal(expected, actual)
73
+ end
74
+
75
+ def test_relationship_many_links
76
+ expected = {
77
+ links: {
78
+ self: 'a link',
79
+ related: 'another link'
80
+ }
81
+ }
82
+
83
+ model_attributes = { blog: :does_not_matter }
84
+ relationship_name = :blog
85
+ model = new_model(model_attributes)
86
+ actual = build_serializer_and_serialize_relationship(model, relationship_name) do
87
+ has_one :blog do
88
+ include_data false
89
+ link :self, 'a link'
90
+ link :related, 'another link'
91
+ end
92
+ end
93
+ assert_equal(expected, actual)
94
+ end
95
+
96
+ def test_relationship_block_link_with_meta
97
+ expected = {
98
+ links: {
99
+ self: {
100
+ href: '1',
101
+ meta: { id: 1 }
102
+ }
103
+ }
104
+ }
105
+
106
+ model_attributes = { blog: Blog.new(id: 1) }
107
+ relationship_name = :blog
108
+ model = new_model(model_attributes)
109
+ actual = build_serializer_and_serialize_relationship(model, relationship_name) do
110
+ has_one :blog do
111
+ include_data false
112
+ link :self do
113
+ href object.blog.id.to_s
114
+ meta(id: object.blog.id)
115
+ end
116
+ end
117
+ end
118
+ assert_equal(expected, actual)
119
+ end
120
+
121
+ def test_relationship_simple_meta
122
+ expected = { meta: { id: '1' } }
123
+
124
+ model_attributes = { blog: Blog.new(id: 1) }
125
+ relationship_name = :blog
126
+ model = new_model(model_attributes)
127
+ actual = build_serializer_and_serialize_relationship(model, relationship_name) do
128
+ has_one :blog do
129
+ include_data false
130
+ meta(id: object.blog.id.to_s)
131
+ end
132
+ end
133
+ assert_equal(expected, actual)
134
+ end
135
+
136
+ def test_relationship_block_meta
137
+ expected = {
138
+ meta: {
139
+ id: 1
140
+ }
141
+ }
142
+
143
+ model_attributes = { blog: Blog.new(id: 1) }
144
+ relationship_name = :blog
145
+ model = new_model(model_attributes)
146
+ actual = build_serializer_and_serialize_relationship(model, relationship_name) do
147
+ has_one :blog do
148
+ include_data false
149
+ meta(id: object.blog.id)
150
+ end
151
+ end
152
+ assert_equal(expected, actual)
153
+ end
154
+
155
+ def test_relationship_simple_link
156
+ expected = {
157
+ data: {
158
+ id: '1337',
159
+ type: 'bios'
160
+ },
161
+ links: {
162
+ self: '//example.com/link_author/relationships/bio'
163
+ }
164
+ }
165
+
166
+ model_attributes = { bio: Bio.new(id: 1337) }
167
+ relationship_name = :bio
168
+ model = new_model(model_attributes)
169
+ actual = build_serializer_and_serialize_relationship(model, relationship_name) do
170
+ has_one :bio do
171
+ link :self, '//example.com/link_author/relationships/bio'
172
+ end
173
+ end
174
+ assert_equal(expected, actual)
175
+ end
176
+
177
+ def test_relationship_block_link
178
+ expected = {
179
+ data: { id: '1337', type: 'profiles' },
180
+ links: { related: '//example.com/profiles/1337' }
181
+ }
182
+
183
+ model_attributes = { profile: Profile.new(id: 1337) }
184
+ relationship_name = :profile
185
+ model = new_model(model_attributes)
186
+ actual = build_serializer_and_serialize_relationship(model, relationship_name) do
187
+ has_one :profile do
188
+ id = object.profile.id
189
+ link :related do
190
+ "//example.com/profiles/#{id}" if id != 123
191
+ end
192
+ end
193
+ end
194
+ assert_equal(expected, actual)
195
+ end
196
+
197
+ def test_relationship_with_everything
198
+ expected = {
199
+ data: [{ id: '1337', type: 'likes' }],
200
+ links: {
201
+ related: {
202
+ href: '//example.com/likes/1337',
203
+ meta: { ids: '1337' }
204
+ }
205
+ },
206
+ meta: { liked: true }
207
+ }
208
+
209
+ model_attributes = { likes: [Like.new(id: 1337)] }
210
+ relationship_name = :likes
211
+ model = new_model(model_attributes)
212
+ actual = build_serializer_and_serialize_relationship(model, relationship_name) do
213
+ has_many :likes do
214
+ link :related do
215
+ ids = object.likes.map(&:id).join(',')
216
+ href "//example.com/likes/#{ids}"
217
+ meta ids: ids
218
+ end
219
+ meta liked: object.likes.any?
220
+ end
221
+ end
222
+ assert_equal(expected, actual)
223
+ end
224
+
225
+ def test_relationship_nil_link
226
+ expected = {
227
+ data: { id: '123', type: 'profiles' }
228
+ }
229
+
230
+ model_attributes = { profile: Profile.new(id: 123) }
231
+ relationship_name = :profile
232
+ model = new_model(model_attributes)
233
+ actual = build_serializer_and_serialize_relationship(model, relationship_name) do
234
+ has_one :profile do
235
+ id = object.profile.id
236
+ link :related do
237
+ "//example.com/profiles/#{id}" if id != 123
238
+ end
239
+ end
240
+ end
241
+ assert_equal(expected, actual)
242
+ end
243
+
244
+ def test_relationship_block_link_href
245
+ expected = {
246
+ data: [{ id: '1337', type: 'locations' }],
247
+ links: {
248
+ related: { href: '//example.com/locations/1337' }
249
+ }
250
+ }
251
+
252
+ model_attributes = { locations: [Location.new(id: 1337)] }
253
+ relationship_name = :locations
254
+ model = new_model(model_attributes)
255
+ actual = build_serializer_and_serialize_relationship(model, relationship_name) do
256
+ has_many :locations do
257
+ link :related do
258
+ ids = object.locations.map(&:id).join(',')
259
+ href "//example.com/locations/#{ids}"
260
+ end
261
+ end
262
+ end
263
+ assert_equal(expected, actual)
264
+ end
265
+
266
+ def test_relationship_block_link_href_and_meta
267
+ expected = {
268
+ data: [{ id: '1337', type: 'posts' }],
269
+ links: {
270
+ related: {
271
+ href: '//example.com/posts/1337',
272
+ meta: { ids: '1337' }
273
+ }
274
+ }
275
+ }
276
+
277
+ model_attributes = { posts: [Post.new(id: 1337, comments: [], author: nil)] }
278
+ relationship_name = :posts
279
+ model = new_model(model_attributes)
280
+ actual = build_serializer_and_serialize_relationship(model, relationship_name) do
281
+ has_many :posts do
282
+ link :related do
283
+ ids = object.posts.map(&:id).join(',')
284
+ href "//example.com/posts/#{ids}"
285
+ meta ids: ids
286
+ end
287
+ end
288
+ end
289
+ assert_equal(expected, actual)
290
+ end
291
+
292
+ def test_relationship_block_link_meta
293
+ expected = {
294
+ data: [{ id: '1337', type: 'comments' }],
295
+ links: {
296
+ self: {
297
+ meta: { ids: [1] }
298
+ }
299
+ }
300
+ }
301
+
302
+ model_attributes = { comments: [Comment.new(id: 1337)] }
303
+ relationship_name = :comments
304
+ model = new_model(model_attributes)
305
+ actual = build_serializer_and_serialize_relationship(model, relationship_name) do
306
+ has_many :comments do
307
+ link :self do
308
+ meta ids: [1]
309
+ end
310
+ end
311
+ end
312
+ assert_equal(expected, actual)
313
+ end
314
+
315
+ def test_relationship_meta
316
+ expected = {
317
+ data: [{ id: 'from-serializer-method', type: 'roles' }],
318
+ meta: { count: 1 }
319
+ }
320
+
321
+ model_attributes = { roles: [Role.new(id: 'from-record')] }
322
+ relationship_name = :roles
323
+ model = new_model(model_attributes)
324
+ actual = build_serializer_and_serialize_relationship(model, relationship_name) do
325
+ has_many :roles do |serializer|
326
+ meta count: object.roles.count
327
+ serializer.cached_roles
328
+ end
329
+ def cached_roles
330
+ [
331
+ Role.new(id: 'from-serializer-method')
332
+ ]
333
+ end
334
+ end
335
+ assert_equal(expected, actual)
336
+ end
337
+
338
+ def test_relationship_not_including_data
339
+ expected = {
340
+ links: { self: '//example.com/link_author/relationships/blog' }
341
+ }
342
+
343
+ model_attributes = { blog: Object }
344
+ relationship_name = :blog
345
+ model = new_model(model_attributes)
346
+ model.define_singleton_method(:read_attribute_for_serialization) do |attr|
347
+ fail 'should not be called' if attr == :blog
348
+ super(attr)
349
+ end
350
+ assert_nothing_raised do
351
+ actual = build_serializer_and_serialize_relationship(model, relationship_name) do
352
+ has_one :blog do
353
+ link :self, '//example.com/link_author/relationships/blog'
354
+ include_data false
355
+ end
356
+ end
357
+ assert_equal(expected, actual)
358
+ end
359
+ end
360
+
361
+ def test_relationship_including_data_explicit
362
+ expected = {
363
+ data: { id: '1337', type: 'authors' },
364
+ meta: { name: 'Dan Brown' }
365
+ }
366
+
367
+ model_attributes = { reviewer: Author.new(id: 1337) }
368
+ relationship_name = :reviewer
369
+ model = new_model(model_attributes)
370
+ actual = build_serializer_and_serialize_relationship(model, relationship_name) do
371
+ belongs_to :reviewer do
372
+ meta name: 'Dan Brown'
373
+ include_data true
374
+ end
375
+ end
376
+ assert_equal(expected, actual)
377
+ end
378
+
379
+ private
380
+
381
+ def build_serializer_and_serialize_relationship(model, relationship_name, &block)
382
+ serializer_class = Class.new(ActiveModel::Serializer, &block)
383
+ hash = serializable(model, serializer: serializer_class, adapter: :json_api).serializable_hash
384
+ hash[:data][:relationships][relationship_name]
385
+ end
386
+
387
+ def new_model(model_attributes)
388
+ Class.new(ActiveModelSerializers::Model) do
389
+ attributes(*model_attributes.keys)
390
+
391
+ def self.name
392
+ 'TestModel'
393
+ end
394
+ end.new(model_attributes)
395
+ end
396
+ end
397
+ end
398
+ end
399
+ end