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,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveModelSerializers
4
+ module Adapter
5
+ class Json < Base
6
+ def serializable_hash(options = nil)
7
+ options = serialization_options(options)
8
+ serialized_hash = { root => Attributes.new(serializer, instance_options).serializable_hash(options) }
9
+ serialized_hash[meta_key] = meta unless meta.blank?
10
+
11
+ self.class.transform_key_casing!(serialized_hash, instance_options)
12
+ end
13
+
14
+ def meta
15
+ instance_options.fetch(:meta, nil)
16
+ end
17
+
18
+ def meta_key
19
+ instance_options.fetch(:meta_key, 'meta'.freeze)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,535 @@
1
+ # frozen_string_literal: true
2
+
3
+ # {http://jsonapi.org/format/ JSON API specification}
4
+ # rubocop:disable Style/AsciiComments
5
+ # TODO: implement!
6
+ # ☐ https://github.com/rails-api/active_model_serializers/issues/1235
7
+ # TODO: use uri_template in link generation?
8
+ # ☐ https://github.com/rails-api/active_model_serializers/pull/1282#discussion_r42528812
9
+ # see gem https://github.com/hannesg/uri_template
10
+ # spec http://tools.ietf.org/html/rfc6570
11
+ # impl https://developer.github.com/v3/#schema https://api.github.com/
12
+ # TODO: validate against a JSON schema document?
13
+ # ☐ https://github.com/rails-api/active_model_serializers/issues/1162
14
+ # ☑ https://github.com/rails-api/active_model_serializers/pull/1270
15
+ # TODO: Routing
16
+ # ☐ https://github.com/rails-api/active_model_serializers/pull/1476
17
+ # TODO: Query Params
18
+ # ☑ `include` https://github.com/rails-api/active_model_serializers/pull/1131
19
+ # ☑ `fields` https://github.com/rails-api/active_model_serializers/pull/700
20
+ # ☑ `page[number]=3&page[size]=1` https://github.com/rails-api/active_model_serializers/pull/1041
21
+ # ☐ `filter`
22
+ # ☐ `sort`
23
+ module ActiveModelSerializers
24
+ module Adapter
25
+ class JsonApi < Base
26
+ extend ActiveSupport::Autoload
27
+ eager_autoload do
28
+ autoload :Jsonapi
29
+ autoload :ResourceIdentifier
30
+ autoload :Link
31
+ autoload :PaginationLinks
32
+ autoload :Meta
33
+ autoload :Error
34
+ autoload :Deserialization
35
+ autoload :Relationship
36
+ end
37
+
38
+ def self.default_key_transform
39
+ :dash
40
+ end
41
+
42
+ def self.fragment_cache(cached_hash, non_cached_hash, root = true)
43
+ core_cached = cached_hash.first
44
+ core_non_cached = non_cached_hash.first
45
+ no_root_cache = cached_hash.delete_if { |key, _value| key == core_cached[0] }
46
+ no_root_non_cache = non_cached_hash.delete_if { |key, _value| key == core_non_cached[0] }
47
+ cached_resource = (core_cached[1]) ? core_cached[1].deep_merge(core_non_cached[1]) : core_non_cached[1]
48
+ hash = root ? { root => cached_resource } : cached_resource
49
+
50
+ hash.deep_merge no_root_non_cache.deep_merge no_root_cache
51
+ end
52
+
53
+ def initialize(serializer, options = {})
54
+ super
55
+ @include_directive = JSONAPI::IncludeDirective.new(options[:include], allow_wildcard: true)
56
+ @fieldset = options[:fieldset] || ActiveModel::Serializer::Fieldset.new(options.delete(:fields))
57
+ end
58
+
59
+ # {http://jsonapi.org/format/#crud Requests are transactional, i.e. success or failure}
60
+ # {http://jsonapi.org/format/#document-top-level data and errors MUST NOT coexist in the same document.}
61
+ def serializable_hash(*)
62
+ document = if serializer.success?
63
+ success_document
64
+ else
65
+ failure_document
66
+ end
67
+ self.class.transform_key_casing!(document, instance_options)
68
+ end
69
+
70
+ def fragment_cache(cached_hash, non_cached_hash)
71
+ root = !instance_options.include?(:include)
72
+ self.class.fragment_cache(cached_hash, non_cached_hash, root)
73
+ end
74
+
75
+ # {http://jsonapi.org/format/#document-top-level Primary data}
76
+ # definition:
77
+ # ☐ toplevel_data (required)
78
+ # ☐ toplevel_included
79
+ # ☑ toplevel_meta
80
+ # ☑ toplevel_links
81
+ # ☑ toplevel_jsonapi
82
+ # structure:
83
+ # {
84
+ # data: toplevel_data,
85
+ # included: toplevel_included,
86
+ # meta: toplevel_meta,
87
+ # links: toplevel_links,
88
+ # jsonapi: toplevel_jsonapi
89
+ # }.reject! {|_,v| v.nil? }
90
+ # rubocop:disable Metrics/CyclomaticComplexity
91
+ def success_document
92
+ is_collection = serializer.respond_to?(:each)
93
+ serializers = is_collection ? serializer : [serializer]
94
+ primary_data, included = resource_objects_for(serializers)
95
+
96
+ hash = {}
97
+ # toplevel_data
98
+ # definition:
99
+ # oneOf
100
+ # resource
101
+ # array of unique items of type 'resource'
102
+ # null
103
+ #
104
+ # description:
105
+ # The document's "primary data" is a representation of the resource or collection of resources
106
+ # targeted by a request.
107
+ #
108
+ # Singular: the resource object.
109
+ #
110
+ # Collection: one of an array of resource objects, an array of resource identifier objects, or
111
+ # an empty array ([]), for requests that target resource collections.
112
+ #
113
+ # None: null if the request is one that might correspond to a single resource, but doesn't currently.
114
+ # structure:
115
+ # if serializable_resource.resource?
116
+ # resource
117
+ # elsif serializable_resource.collection?
118
+ # [
119
+ # resource,
120
+ # resource
121
+ # ]
122
+ # else
123
+ # nil
124
+ # end
125
+ hash[:data] = is_collection ? primary_data : primary_data[0]
126
+ # toplevel_included
127
+ # alias included
128
+ # definition:
129
+ # array of unique items of type 'resource'
130
+ #
131
+ # description:
132
+ # To reduce the number of HTTP requests, servers **MAY** allow
133
+ # responses that include related resources along with the requested primary
134
+ # resources. Such responses are called "compound documents".
135
+ # structure:
136
+ # [
137
+ # resource,
138
+ # resource
139
+ # ]
140
+ hash[:included] = included if included.any?
141
+
142
+ Jsonapi.add!(hash)
143
+
144
+ if instance_options[:links]
145
+ hash[:links] ||= {}
146
+ hash[:links].update(instance_options[:links])
147
+ end
148
+
149
+ if is_collection && serializer.paginated?
150
+ hash[:links] ||= {}
151
+ hash[:links].update(pagination_links_for(serializer))
152
+ end
153
+
154
+ hash[:meta] = instance_options[:meta] unless instance_options[:meta].blank?
155
+
156
+ hash
157
+ end
158
+ # rubocop:enable Metrics/CyclomaticComplexity
159
+
160
+ # {http://jsonapi.org/format/#errors JSON API Errors}
161
+ # TODO: look into caching
162
+ # definition:
163
+ # ☑ toplevel_errors array (required)
164
+ # ☐ toplevel_meta
165
+ # ☐ toplevel_jsonapi
166
+ # structure:
167
+ # {
168
+ # errors: toplevel_errors,
169
+ # meta: toplevel_meta,
170
+ # jsonapi: toplevel_jsonapi
171
+ # }.reject! {|_,v| v.nil? }
172
+ # prs:
173
+ # https://github.com/rails-api/active_model_serializers/pull/1004
174
+ def failure_document
175
+ hash = {}
176
+ # PR Please :)
177
+ # Jsonapi.add!(hash)
178
+
179
+ # toplevel_errors
180
+ # definition:
181
+ # array of unique items of type 'error'
182
+ # structure:
183
+ # [
184
+ # error,
185
+ # error
186
+ # ]
187
+ if serializer.respond_to?(:each)
188
+ hash[:errors] = serializer.flat_map do |error_serializer|
189
+ Error.resource_errors(error_serializer, instance_options)
190
+ end
191
+ else
192
+ hash[:errors] = Error.resource_errors(serializer, instance_options)
193
+ end
194
+ hash
195
+ end
196
+
197
+ protected
198
+
199
+ attr_reader :fieldset
200
+
201
+ private
202
+
203
+ # {http://jsonapi.org/format/#document-resource-objects Primary data}
204
+ # resource
205
+ # definition:
206
+ # JSON Object
207
+ #
208
+ # properties:
209
+ # type (required) : String
210
+ # id (required) : String
211
+ # attributes
212
+ # relationships
213
+ # links
214
+ # meta
215
+ #
216
+ # description:
217
+ # "Resource objects" appear in a JSON API document to represent resources
218
+ # structure:
219
+ # {
220
+ # type: 'admin--some-user',
221
+ # id: '1336',
222
+ # attributes: attributes,
223
+ # relationships: relationships,
224
+ # links: links,
225
+ # meta: meta,
226
+ # }.reject! {|_,v| v.nil? }
227
+ # prs:
228
+ # type
229
+ # https://github.com/rails-api/active_model_serializers/pull/1122
230
+ # [x] https://github.com/rails-api/active_model_serializers/pull/1213
231
+ # https://github.com/rails-api/active_model_serializers/pull/1216
232
+ # https://github.com/rails-api/active_model_serializers/pull/1029
233
+ # links
234
+ # [x] https://github.com/rails-api/active_model_serializers/pull/1246
235
+ # [x] url helpers https://github.com/rails-api/active_model_serializers/issues/1269
236
+ # meta
237
+ # [x] https://github.com/rails-api/active_model_serializers/pull/1340
238
+ def resource_objects_for(serializers)
239
+ @primary = []
240
+ @included = []
241
+ @resource_identifiers = Set.new
242
+ serializers.each { |serializer| process_resource(serializer, true, @include_directive) }
243
+ serializers.each { |serializer| process_relationships(serializer, @include_directive) }
244
+
245
+ [@primary, @included]
246
+ end
247
+
248
+ def process_resource(serializer, primary, include_slice = {})
249
+ resource_identifier = ResourceIdentifier.new(serializer, instance_options).as_json
250
+ return false unless @resource_identifiers.add?(resource_identifier)
251
+
252
+ resource_object = resource_object_for(serializer, include_slice)
253
+ if primary
254
+ @primary << resource_object
255
+ else
256
+ @included << resource_object
257
+ end
258
+
259
+ true
260
+ end
261
+
262
+ def process_relationships(serializer, include_slice)
263
+ serializer.associations(include_slice).each do |association|
264
+ # TODO(BF): Process relationship without evaluating lazy_association
265
+ process_relationship(association.lazy_association.serializer, include_slice[association.key])
266
+ end
267
+ end
268
+
269
+ def process_relationship(serializer, include_slice)
270
+ if serializer.respond_to?(:each)
271
+ serializer.each { |s| process_relationship(s, include_slice) }
272
+ return
273
+ end
274
+ return unless serializer && serializer.object
275
+ return unless process_resource(serializer, false, include_slice)
276
+
277
+ process_relationships(serializer, include_slice)
278
+ end
279
+
280
+ # {http://jsonapi.org/format/#document-resource-object-attributes Document Resource Object Attributes}
281
+ # attributes
282
+ # definition:
283
+ # JSON Object
284
+ #
285
+ # patternProperties:
286
+ # ^(?!relationships$|links$)\\w[-\\w_]*$
287
+ #
288
+ # description:
289
+ # Members of the attributes object ("attributes") represent information about the resource
290
+ # object in which it's defined.
291
+ # Attributes may contain any valid JSON value
292
+ # structure:
293
+ # {
294
+ # foo: 'bar'
295
+ # }
296
+ def attributes_for(serializer, fields)
297
+ serializer.attributes(fields).except(:id)
298
+ end
299
+
300
+ # {http://jsonapi.org/format/#document-resource-objects Document Resource Objects}
301
+ def resource_object_for(serializer, include_slice = {})
302
+ resource_object = data_for(serializer, include_slice)
303
+
304
+ # toplevel_links
305
+ # definition:
306
+ # allOf
307
+ # ☐ links
308
+ # ☐ pagination
309
+ #
310
+ # description:
311
+ # Link members related to the primary data.
312
+ # structure:
313
+ # links.merge!(pagination)
314
+ # prs:
315
+ # https://github.com/rails-api/active_model_serializers/pull/1247
316
+ # https://github.com/rails-api/active_model_serializers/pull/1018
317
+ if (links = links_for(serializer)).any?
318
+ resource_object ||= {}
319
+ resource_object[:links] = links
320
+ end
321
+
322
+ # toplevel_meta
323
+ # alias meta
324
+ # definition:
325
+ # meta
326
+ # structure
327
+ # {
328
+ # :'git-ref' => 'abc123'
329
+ # }
330
+ if (meta = meta_for(serializer)).present?
331
+ resource_object ||= {}
332
+ resource_object[:meta] = meta
333
+ end
334
+
335
+ resource_object
336
+ end
337
+
338
+ def data_for(serializer, include_slice)
339
+ data = serializer.fetch(self) do
340
+ resource_object = ResourceIdentifier.new(serializer, instance_options).as_json
341
+ break nil if resource_object.nil?
342
+
343
+ requested_fields = fieldset && fieldset.fields_for(resource_object[:type])
344
+ attributes = attributes_for(serializer, requested_fields)
345
+ resource_object[:attributes] = attributes if attributes.any?
346
+ resource_object
347
+ end
348
+ data.tap do |resource_object|
349
+ next if resource_object.nil?
350
+ # NOTE(BF): the attributes are cached above, separately from the relationships, below.
351
+ requested_associations = fieldset.fields_for(resource_object[:type]) || '*'
352
+ relationships = relationships_for(serializer, requested_associations, include_slice)
353
+ resource_object[:relationships] = relationships if relationships.any?
354
+ end
355
+ end
356
+
357
+ # {http://jsonapi.org/format/#document-resource-object-relationships Document Resource Object Relationship}
358
+ # relationships
359
+ # definition:
360
+ # JSON Object
361
+ #
362
+ # patternProperties:
363
+ # ^\\w[-\\w_]*$"
364
+ #
365
+ # properties:
366
+ # data : relationshipsData
367
+ # links
368
+ # meta
369
+ #
370
+ # description:
371
+ #
372
+ # Members of the relationships object ("relationships") represent references from the
373
+ # resource object in which it's defined to other resource objects."
374
+ # structure:
375
+ # {
376
+ # links: links,
377
+ # meta: meta,
378
+ # data: relationshipsData
379
+ # }.reject! {|_,v| v.nil? }
380
+ #
381
+ # prs:
382
+ # links
383
+ # [x] https://github.com/rails-api/active_model_serializers/pull/1454
384
+ # meta
385
+ # [x] https://github.com/rails-api/active_model_serializers/pull/1454
386
+ # polymorphic
387
+ # [ ] https://github.com/rails-api/active_model_serializers/pull/1420
388
+ #
389
+ # relationshipsData
390
+ # definition:
391
+ # oneOf
392
+ # relationshipToOne
393
+ # relationshipToMany
394
+ #
395
+ # description:
396
+ # Member, whose value represents "resource linkage"
397
+ # structure:
398
+ # if has_one?
399
+ # relationshipToOne
400
+ # else
401
+ # relationshipToMany
402
+ # end
403
+ #
404
+ # definition:
405
+ # anyOf
406
+ # null
407
+ # linkage
408
+ #
409
+ # relationshipToOne
410
+ # description:
411
+ #
412
+ # References to other resource objects in a to-one ("relationship"). Relationships can be
413
+ # specified by including a member in a resource's links object.
414
+ #
415
+ # None: Describes an empty to-one relationship.
416
+ # structure:
417
+ # if has_related?
418
+ # linkage
419
+ # else
420
+ # nil
421
+ # end
422
+ #
423
+ # relationshipToMany
424
+ # definition:
425
+ # array of unique items of type 'linkage'
426
+ #
427
+ # description:
428
+ # An array of objects each containing "type" and "id" members for to-many relationships
429
+ # structure:
430
+ # [
431
+ # linkage,
432
+ # linkage
433
+ # ]
434
+ # prs:
435
+ # polymorphic
436
+ # [ ] https://github.com/rails-api/active_model_serializers/pull/1282
437
+ #
438
+ # linkage
439
+ # definition:
440
+ # type (required) : String
441
+ # id (required) : String
442
+ # meta
443
+ #
444
+ # description:
445
+ # The "type" and "id" to non-empty members.
446
+ # structure:
447
+ # {
448
+ # type: 'required-type',
449
+ # id: 'required-id',
450
+ # meta: meta
451
+ # }.reject! {|_,v| v.nil? }
452
+ def relationships_for(serializer, requested_associations, include_slice)
453
+ include_directive = JSONAPI::IncludeDirective.new(
454
+ requested_associations,
455
+ allow_wildcard: true
456
+ )
457
+ serializer.associations(include_directive, include_slice).each_with_object({}) do |association, hash|
458
+ hash[association.key] = Relationship.new(serializer, instance_options, association).as_json
459
+ end
460
+ end
461
+
462
+ # {http://jsonapi.org/format/#document-links Document Links}
463
+ # links
464
+ # definition:
465
+ # JSON Object
466
+ #
467
+ # properties:
468
+ # self : URI
469
+ # related : link
470
+ #
471
+ # description:
472
+ # A resource object **MAY** contain references to other resource objects ("relationships").
473
+ # Relationships may be to-one or to-many. Relationships can be specified by including a member
474
+ # in a resource's links object.
475
+ #
476
+ # A `self` member’s value is a URL for the relationship itself (a "relationship URL"). This
477
+ # URL allows the client to directly manipulate the relationship. For example, it would allow
478
+ # a client to remove an `author` from an `article` without deleting the people resource
479
+ # itself.
480
+ # structure:
481
+ # {
482
+ # self: 'http://example.com/etc',
483
+ # related: link
484
+ # }.reject! {|_,v| v.nil? }
485
+ def links_for(serializer)
486
+ serializer._links.each_with_object({}) do |(name, value), hash|
487
+ next if value.excluded?(serializer)
488
+ result = Link.new(serializer, value.block).as_json
489
+ hash[name] = result if result
490
+ end
491
+ end
492
+
493
+ # {http://jsonapi.org/format/#fetching-pagination Pagination Links}
494
+ # pagination
495
+ # definition:
496
+ # first : pageObject
497
+ # last : pageObject
498
+ # prev : pageObject
499
+ # next : pageObject
500
+ # structure:
501
+ # {
502
+ # first: pageObject,
503
+ # last: pageObject,
504
+ # prev: pageObject,
505
+ # next: pageObject
506
+ # }
507
+ #
508
+ # pageObject
509
+ # definition:
510
+ # oneOf
511
+ # URI
512
+ # null
513
+ #
514
+ # description:
515
+ # The <x> page of data
516
+ # structure:
517
+ # if has_page?
518
+ # 'http://example.com/some-page?page[number][x]'
519
+ # else
520
+ # nil
521
+ # end
522
+ # prs:
523
+ # https://github.com/rails-api/active_model_serializers/pull/1041
524
+ def pagination_links_for(serializer)
525
+ PaginationLinks.new(serializer.object, instance_options).as_json
526
+ end
527
+
528
+ # {http://jsonapi.org/format/#document-meta Docment Meta}
529
+ def meta_for(serializer)
530
+ Meta.new(serializer).as_json
531
+ end
532
+ end
533
+ end
534
+ end
535
+ # rubocop:enable Style/AsciiComments