agi_active_model_serializers 0.10.7

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 (220) 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 +102 -0
  6. data/.simplecov +110 -0
  7. data/.travis.yml +51 -0
  8. data/CHANGELOG.md +612 -0
  9. data/CODE_OF_CONDUCT.md +74 -0
  10. data/CONTRIBUTING.md +105 -0
  11. data/Gemfile +56 -0
  12. data/MIT-LICENSE +22 -0
  13. data/README.md +307 -0
  14. data/Rakefile +103 -0
  15. data/active_model_serializers.gemspec +63 -0
  16. data/appveyor.yml +24 -0
  17. data/bin/bench +171 -0
  18. data/bin/bench_regression +316 -0
  19. data/bin/serve_benchmark +39 -0
  20. data/docs/README.md +41 -0
  21. data/docs/STYLE.md +58 -0
  22. data/docs/general/adapters.md +247 -0
  23. data/docs/general/caching.md +58 -0
  24. data/docs/general/configuration_options.md +169 -0
  25. data/docs/general/deserialization.md +100 -0
  26. data/docs/general/fields.md +31 -0
  27. data/docs/general/getting_started.md +133 -0
  28. data/docs/general/instrumentation.md +40 -0
  29. data/docs/general/key_transforms.md +40 -0
  30. data/docs/general/logging.md +14 -0
  31. data/docs/general/rendering.md +279 -0
  32. data/docs/general/serializers.md +461 -0
  33. data/docs/how-open-source-maintained.jpg +0 -0
  34. data/docs/howto/add_pagination_links.md +138 -0
  35. data/docs/howto/add_relationship_links.md +137 -0
  36. data/docs/howto/add_root_key.md +55 -0
  37. data/docs/howto/grape_integration.md +42 -0
  38. data/docs/howto/outside_controller_use.md +65 -0
  39. data/docs/howto/passing_arbitrary_options.md +27 -0
  40. data/docs/howto/serialize_poro.md +32 -0
  41. data/docs/howto/test.md +154 -0
  42. data/docs/howto/upgrade_from_0_8_to_0_10.md +265 -0
  43. data/docs/integrations/ember-and-json-api.md +144 -0
  44. data/docs/integrations/grape.md +19 -0
  45. data/docs/jsonapi/errors.md +56 -0
  46. data/docs/jsonapi/schema.md +151 -0
  47. data/docs/jsonapi/schema/schema.json +366 -0
  48. data/docs/rfcs/0000-namespace.md +106 -0
  49. data/docs/rfcs/template.md +15 -0
  50. data/lib/action_controller/serialization.rb +66 -0
  51. data/lib/active_model/serializable_resource.rb +11 -0
  52. data/lib/active_model/serializer.rb +231 -0
  53. data/lib/active_model/serializer/adapter.rb +24 -0
  54. data/lib/active_model/serializer/adapter/attributes.rb +15 -0
  55. data/lib/active_model/serializer/adapter/base.rb +18 -0
  56. data/lib/active_model/serializer/adapter/json.rb +15 -0
  57. data/lib/active_model/serializer/adapter/json_api.rb +15 -0
  58. data/lib/active_model/serializer/adapter/null.rb +15 -0
  59. data/lib/active_model/serializer/array_serializer.rb +12 -0
  60. data/lib/active_model/serializer/association.rb +34 -0
  61. data/lib/active_model/serializer/attribute.rb +25 -0
  62. data/lib/active_model/serializer/belongs_to_reflection.rb +7 -0
  63. data/lib/active_model/serializer/collection_reflection.rb +7 -0
  64. data/lib/active_model/serializer/collection_serializer.rb +87 -0
  65. data/lib/active_model/serializer/concerns/associations.rb +102 -0
  66. data/lib/active_model/serializer/concerns/attributes.rb +82 -0
  67. data/lib/active_model/serializer/concerns/caching.rb +292 -0
  68. data/lib/active_model/serializer/concerns/configuration.rb +59 -0
  69. data/lib/active_model/serializer/concerns/links.rb +35 -0
  70. data/lib/active_model/serializer/concerns/meta.rb +29 -0
  71. data/lib/active_model/serializer/concerns/type.rb +25 -0
  72. data/lib/active_model/serializer/error_serializer.rb +14 -0
  73. data/lib/active_model/serializer/errors_serializer.rb +32 -0
  74. data/lib/active_model/serializer/field.rb +90 -0
  75. data/lib/active_model/serializer/fieldset.rb +31 -0
  76. data/lib/active_model/serializer/has_many_reflection.rb +7 -0
  77. data/lib/active_model/serializer/has_one_reflection.rb +7 -0
  78. data/lib/active_model/serializer/lint.rb +150 -0
  79. data/lib/active_model/serializer/null.rb +17 -0
  80. data/lib/active_model/serializer/reflection.rb +163 -0
  81. data/lib/active_model/serializer/singular_reflection.rb +7 -0
  82. data/lib/active_model/serializer/version.rb +5 -0
  83. data/lib/active_model_serializers.rb +53 -0
  84. data/lib/active_model_serializers/adapter.rb +98 -0
  85. data/lib/active_model_serializers/adapter/attributes.rb +13 -0
  86. data/lib/active_model_serializers/adapter/base.rb +83 -0
  87. data/lib/active_model_serializers/adapter/json.rb +21 -0
  88. data/lib/active_model_serializers/adapter/json_api.rb +517 -0
  89. data/lib/active_model_serializers/adapter/json_api/deserialization.rb +213 -0
  90. data/lib/active_model_serializers/adapter/json_api/error.rb +96 -0
  91. data/lib/active_model_serializers/adapter/json_api/jsonapi.rb +49 -0
  92. data/lib/active_model_serializers/adapter/json_api/link.rb +83 -0
  93. data/lib/active_model_serializers/adapter/json_api/meta.rb +37 -0
  94. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +69 -0
  95. data/lib/active_model_serializers/adapter/json_api/relationship.rb +63 -0
  96. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +51 -0
  97. data/lib/active_model_serializers/adapter/null.rb +9 -0
  98. data/lib/active_model_serializers/callbacks.rb +55 -0
  99. data/lib/active_model_serializers/deprecate.rb +54 -0
  100. data/lib/active_model_serializers/deserialization.rb +15 -0
  101. data/lib/active_model_serializers/json_pointer.rb +14 -0
  102. data/lib/active_model_serializers/logging.rb +122 -0
  103. data/lib/active_model_serializers/lookup_chain.rb +80 -0
  104. data/lib/active_model_serializers/model.rb +71 -0
  105. data/lib/active_model_serializers/railtie.rb +48 -0
  106. data/lib/active_model_serializers/register_jsonapi_renderer.rb +78 -0
  107. data/lib/active_model_serializers/serializable_resource.rb +82 -0
  108. data/lib/active_model_serializers/serialization_context.rb +39 -0
  109. data/lib/active_model_serializers/test.rb +7 -0
  110. data/lib/active_model_serializers/test/schema.rb +138 -0
  111. data/lib/active_model_serializers/test/serializer.rb +125 -0
  112. data/lib/generators/rails/USAGE +6 -0
  113. data/lib/generators/rails/resource_override.rb +10 -0
  114. data/lib/generators/rails/serializer_generator.rb +36 -0
  115. data/lib/generators/rails/templates/serializer.rb.erb +15 -0
  116. data/lib/grape/active_model_serializers.rb +16 -0
  117. data/lib/grape/formatters/active_model_serializers.rb +32 -0
  118. data/lib/grape/helpers/active_model_serializers.rb +17 -0
  119. data/test/action_controller/adapter_selector_test.rb +53 -0
  120. data/test/action_controller/explicit_serializer_test.rb +135 -0
  121. data/test/action_controller/json/include_test.rb +246 -0
  122. data/test/action_controller/json_api/deserialization_test.rb +112 -0
  123. data/test/action_controller/json_api/errors_test.rb +40 -0
  124. data/test/action_controller/json_api/fields_test.rb +66 -0
  125. data/test/action_controller/json_api/linked_test.rb +202 -0
  126. data/test/action_controller/json_api/pagination_test.rb +116 -0
  127. data/test/action_controller/json_api/transform_test.rb +189 -0
  128. data/test/action_controller/lookup_proc_test.rb +49 -0
  129. data/test/action_controller/namespace_lookup_test.rb +232 -0
  130. data/test/action_controller/serialization_scope_name_test.rb +229 -0
  131. data/test/action_controller/serialization_test.rb +472 -0
  132. data/test/active_model_serializers/adapter_for_test.rb +208 -0
  133. data/test/active_model_serializers/json_pointer_test.rb +22 -0
  134. data/test/active_model_serializers/logging_test.rb +77 -0
  135. data/test/active_model_serializers/model_test.rb +69 -0
  136. data/test/active_model_serializers/railtie_test_isolated.rb +63 -0
  137. data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +161 -0
  138. data/test/active_model_serializers/serialization_context_test_isolated.rb +71 -0
  139. data/test/active_model_serializers/test/schema_test.rb +131 -0
  140. data/test/active_model_serializers/test/serializer_test.rb +62 -0
  141. data/test/active_record_test.rb +9 -0
  142. data/test/adapter/attributes_test.rb +43 -0
  143. data/test/adapter/deprecation_test.rb +100 -0
  144. data/test/adapter/json/belongs_to_test.rb +45 -0
  145. data/test/adapter/json/collection_test.rb +104 -0
  146. data/test/adapter/json/has_many_test.rb +45 -0
  147. data/test/adapter/json/transform_test.rb +93 -0
  148. data/test/adapter/json_api/belongs_to_test.rb +155 -0
  149. data/test/adapter/json_api/collection_test.rb +96 -0
  150. data/test/adapter/json_api/errors_test.rb +76 -0
  151. data/test/adapter/json_api/fields_test.rb +96 -0
  152. data/test/adapter/json_api/has_many_embed_ids_test.rb +43 -0
  153. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +96 -0
  154. data/test/adapter/json_api/has_many_test.rb +165 -0
  155. data/test/adapter/json_api/has_one_test.rb +80 -0
  156. data/test/adapter/json_api/include_data_if_sideloaded_test.rb +168 -0
  157. data/test/adapter/json_api/json_api_test.rb +33 -0
  158. data/test/adapter/json_api/linked_test.rb +413 -0
  159. data/test/adapter/json_api/links_test.rb +95 -0
  160. data/test/adapter/json_api/pagination_links_test.rb +193 -0
  161. data/test/adapter/json_api/parse_test.rb +137 -0
  162. data/test/adapter/json_api/relationship_test.rb +397 -0
  163. data/test/adapter/json_api/resource_identifier_test.rb +110 -0
  164. data/test/adapter/json_api/resource_meta_test.rb +100 -0
  165. data/test/adapter/json_api/toplevel_jsonapi_test.rb +82 -0
  166. data/test/adapter/json_api/transform_test.rb +512 -0
  167. data/test/adapter/json_api/type_test.rb +61 -0
  168. data/test/adapter/json_test.rb +46 -0
  169. data/test/adapter/null_test.rb +22 -0
  170. data/test/adapter/polymorphic_test.rb +171 -0
  171. data/test/adapter_test.rb +67 -0
  172. data/test/array_serializer_test.rb +22 -0
  173. data/test/benchmark/app.rb +65 -0
  174. data/test/benchmark/benchmarking_support.rb +67 -0
  175. data/test/benchmark/bm_active_record.rb +81 -0
  176. data/test/benchmark/bm_adapter.rb +38 -0
  177. data/test/benchmark/bm_caching.rb +119 -0
  178. data/test/benchmark/bm_lookup_chain.rb +83 -0
  179. data/test/benchmark/bm_transform.rb +45 -0
  180. data/test/benchmark/config.ru +3 -0
  181. data/test/benchmark/controllers.rb +83 -0
  182. data/test/benchmark/fixtures.rb +219 -0
  183. data/test/cache_test.rb +595 -0
  184. data/test/collection_serializer_test.rb +123 -0
  185. data/test/fixtures/active_record.rb +113 -0
  186. data/test/fixtures/poro.rb +232 -0
  187. data/test/generators/scaffold_controller_generator_test.rb +24 -0
  188. data/test/generators/serializer_generator_test.rb +74 -0
  189. data/test/grape_test.rb +178 -0
  190. data/test/lint_test.rb +49 -0
  191. data/test/logger_test.rb +20 -0
  192. data/test/poro_test.rb +9 -0
  193. data/test/serializable_resource_test.rb +79 -0
  194. data/test/serializers/association_macros_test.rb +37 -0
  195. data/test/serializers/associations_test.rb +383 -0
  196. data/test/serializers/attribute_test.rb +153 -0
  197. data/test/serializers/attributes_test.rb +52 -0
  198. data/test/serializers/caching_configuration_test_isolated.rb +170 -0
  199. data/test/serializers/configuration_test.rb +32 -0
  200. data/test/serializers/fieldset_test.rb +14 -0
  201. data/test/serializers/meta_test.rb +202 -0
  202. data/test/serializers/options_test.rb +32 -0
  203. data/test/serializers/read_attribute_for_serialization_test.rb +79 -0
  204. data/test/serializers/root_test.rb +21 -0
  205. data/test/serializers/serialization_test.rb +55 -0
  206. data/test/serializers/serializer_for_test.rb +136 -0
  207. data/test/serializers/serializer_for_with_namespace_test.rb +88 -0
  208. data/test/support/custom_schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
  209. data/test/support/isolated_unit.rb +82 -0
  210. data/test/support/rails5_shims.rb +53 -0
  211. data/test/support/rails_app.rb +36 -0
  212. data/test/support/schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
  213. data/test/support/schemas/active_model_serializers/test/schema_test/my/show.json +6 -0
  214. data/test/support/schemas/custom/show.json +7 -0
  215. data/test/support/schemas/hyper_schema.json +93 -0
  216. data/test/support/schemas/render_using_json_api.json +43 -0
  217. data/test/support/schemas/simple_json_pointers.json +10 -0
  218. data/test/support/serialization_testing.rb +71 -0
  219. data/test/test_helper.rb +58 -0
  220. metadata +602 -0
@@ -0,0 +1,213 @@
1
+ module ActiveModelSerializers
2
+ module Adapter
3
+ class JsonApi
4
+ # NOTE(Experimental):
5
+ # This is an experimental feature. Both the interface and internals could be subject
6
+ # to changes.
7
+ module Deserialization
8
+ InvalidDocument = Class.new(ArgumentError)
9
+
10
+ module_function
11
+
12
+ # Transform a JSON API document, containing a single data object,
13
+ # into a hash that is ready for ActiveRecord::Base.new() and such.
14
+ # Raises InvalidDocument if the payload is not properly formatted.
15
+ #
16
+ # @param [Hash|ActionController::Parameters] document
17
+ # @param [Hash] options
18
+ # only: Array of symbols of whitelisted fields.
19
+ # except: Array of symbols of blacklisted fields.
20
+ # keys: Hash of translated keys (e.g. :author => :user).
21
+ # polymorphic: Array of symbols of polymorphic fields.
22
+ # @return [Hash]
23
+ #
24
+ # @example
25
+ # document = {
26
+ # data: {
27
+ # id: 1,
28
+ # type: 'post',
29
+ # attributes: {
30
+ # title: 'Title 1',
31
+ # date: '2015-12-20'
32
+ # },
33
+ # associations: {
34
+ # author: {
35
+ # data: {
36
+ # type: 'user',
37
+ # id: 2
38
+ # }
39
+ # },
40
+ # second_author: {
41
+ # data: nil
42
+ # },
43
+ # comments: {
44
+ # data: [{
45
+ # type: 'comment',
46
+ # id: 3
47
+ # },{
48
+ # type: 'comment',
49
+ # id: 4
50
+ # }]
51
+ # }
52
+ # }
53
+ # }
54
+ # }
55
+ #
56
+ # parse(document) #=>
57
+ # # {
58
+ # # title: 'Title 1',
59
+ # # date: '2015-12-20',
60
+ # # author_id: 2,
61
+ # # second_author_id: nil
62
+ # # comment_ids: [3, 4]
63
+ # # }
64
+ #
65
+ # parse(document, only: [:title, :date, :author],
66
+ # keys: { date: :published_at },
67
+ # polymorphic: [:author]) #=>
68
+ # # {
69
+ # # title: 'Title 1',
70
+ # # published_at: '2015-12-20',
71
+ # # author_id: '2',
72
+ # # author_type: 'people'
73
+ # # }
74
+ #
75
+ def parse!(document, options = {})
76
+ parse(document, options) do |invalid_payload, reason|
77
+ fail InvalidDocument, "Invalid payload (#{reason}): #{invalid_payload}"
78
+ end
79
+ end
80
+
81
+ # Same as parse!, but returns an empty hash instead of raising InvalidDocument
82
+ # on invalid payloads.
83
+ def parse(document, options = {})
84
+ document = document.dup.permit!.to_h if document.is_a?(ActionController::Parameters)
85
+
86
+ validate_payload(document) do |invalid_document, reason|
87
+ yield invalid_document, reason if block_given?
88
+ return {}
89
+ end
90
+
91
+ primary_data = document['data']
92
+ attributes = primary_data['attributes'] || {}
93
+ attributes['id'] = primary_data['id'] if primary_data['id']
94
+ relationships = primary_data['relationships'] || {}
95
+
96
+ filter_fields(attributes, options)
97
+ filter_fields(relationships, options)
98
+
99
+ hash = {}
100
+ hash.merge!(parse_attributes(attributes, options))
101
+ hash.merge!(parse_relationships(relationships, options))
102
+
103
+ hash
104
+ end
105
+
106
+ # Checks whether a payload is compliant with the JSON API spec.
107
+ #
108
+ # @api private
109
+ # rubocop:disable Metrics/CyclomaticComplexity
110
+ def validate_payload(payload)
111
+ unless payload.is_a?(Hash)
112
+ yield payload, 'Expected hash'
113
+ return
114
+ end
115
+
116
+ primary_data = payload['data']
117
+ unless primary_data.is_a?(Hash)
118
+ yield payload, { data: 'Expected hash' }
119
+ return
120
+ end
121
+
122
+ attributes = primary_data['attributes'] || {}
123
+ unless attributes.is_a?(Hash)
124
+ yield payload, { data: { attributes: 'Expected hash or nil' } }
125
+ return
126
+ end
127
+
128
+ relationships = primary_data['relationships'] || {}
129
+ unless relationships.is_a?(Hash)
130
+ yield payload, { data: { relationships: 'Expected hash or nil' } }
131
+ return
132
+ end
133
+
134
+ relationships.each do |(key, value)|
135
+ unless value.is_a?(Hash) && value.key?('data')
136
+ yield payload, { data: { relationships: { key => 'Expected hash with :data key' } } }
137
+ end
138
+ end
139
+ end
140
+ # rubocop:enable Metrics/CyclomaticComplexity
141
+
142
+ # @api private
143
+ def filter_fields(fields, options)
144
+ if (only = options[:only])
145
+ fields.slice!(*Array(only).map(&:to_s))
146
+ elsif (except = options[:except])
147
+ fields.except!(*Array(except).map(&:to_s))
148
+ end
149
+ end
150
+
151
+ # @api private
152
+ def field_key(field, options)
153
+ (options[:keys] || {}).fetch(field.to_sym, field).to_sym
154
+ end
155
+
156
+ # @api private
157
+ def parse_attributes(attributes, options)
158
+ transform_keys(attributes, options)
159
+ .map { |(k, v)| { field_key(k, options) => v } }
160
+ .reduce({}, :merge)
161
+ end
162
+
163
+ # Given an association name, and a relationship data attribute, build a hash
164
+ # mapping the corresponding ActiveRecord attribute to the corresponding value.
165
+ #
166
+ # @example
167
+ # parse_relationship(:comments, [{ 'id' => '1', 'type' => 'comments' },
168
+ # { 'id' => '2', 'type' => 'comments' }],
169
+ # {})
170
+ # # => { :comment_ids => ['1', '2'] }
171
+ # parse_relationship(:author, { 'id' => '1', 'type' => 'users' }, {})
172
+ # # => { :author_id => '1' }
173
+ # parse_relationship(:author, nil, {})
174
+ # # => { :author_id => nil }
175
+ # @param [Symbol] assoc_name
176
+ # @param [Hash] assoc_data
177
+ # @param [Hash] options
178
+ # @return [Hash{Symbol, Object}]
179
+ #
180
+ # @api private
181
+ def parse_relationship(assoc_name, assoc_data, options)
182
+ prefix_key = field_key(assoc_name, options).to_s.singularize
183
+ hash =
184
+ if assoc_data.is_a?(Array)
185
+ { "#{prefix_key}_ids".to_sym => assoc_data.map { |ri| ri['id'] } }
186
+ else
187
+ { "#{prefix_key}_id".to_sym => assoc_data ? assoc_data['id'] : nil }
188
+ end
189
+
190
+ polymorphic = (options[:polymorphic] || []).include?(assoc_name.to_sym)
191
+ if polymorphic
192
+ hash["#{prefix_key}_type".to_sym] = assoc_data.present? ? assoc_data['type'] : nil
193
+ end
194
+
195
+ hash
196
+ end
197
+
198
+ # @api private
199
+ def parse_relationships(relationships, options)
200
+ transform_keys(relationships, options)
201
+ .map { |(k, v)| parse_relationship(k, v['data'], options) }
202
+ .reduce({}, :merge)
203
+ end
204
+
205
+ # @api private
206
+ def transform_keys(hash, options)
207
+ transform = options[:key_transform] || :underscore
208
+ CaseTransform.send(transform, hash)
209
+ end
210
+ end
211
+ end
212
+ end
213
+ end
@@ -0,0 +1,96 @@
1
+ module ActiveModelSerializers
2
+ module Adapter
3
+ class JsonApi < Base
4
+ module Error
5
+ # rubocop:disable Style/AsciiComments
6
+ UnknownSourceTypeError = Class.new(ArgumentError)
7
+
8
+ # Builds a JSON API Errors Object
9
+ # {http://jsonapi.org/format/#errors JSON API Errors}
10
+ #
11
+ # @param [ActiveModel::Serializer::ErrorSerializer] error_serializer
12
+ # @return [Array<Symbol, Array<String>>] i.e. attribute_name, [attribute_errors]
13
+ def self.resource_errors(error_serializer, options)
14
+ error_serializer.as_json.flat_map do |attribute_name, attribute_errors|
15
+ attribute_name = JsonApi.send(:transform_key_casing!, attribute_name,
16
+ options)
17
+ attribute_error_objects(attribute_name, attribute_errors)
18
+ end
19
+ end
20
+
21
+ # definition:
22
+ # JSON Object
23
+ #
24
+ # properties:
25
+ # ☐ id : String
26
+ # ☐ status : String
27
+ # ☐ code : String
28
+ # ☐ title : String
29
+ # ☑ detail : String
30
+ # ☐ links
31
+ # ☐ meta
32
+ # ☑ error_source
33
+ #
34
+ # description:
35
+ # id : A unique identifier for this particular occurrence of the problem.
36
+ # status : The HTTP status code applicable to this problem, expressed as a string value
37
+ # code : An application-specific error code, expressed as a string value.
38
+ # title : A short, human-readable summary of the problem. It **SHOULD NOT** change from
39
+ # occurrence to occurrence of the problem, except for purposes of localization.
40
+ # detail : A human-readable explanation specific to this occurrence of the problem.
41
+ # structure:
42
+ # {
43
+ # title: 'SystemFailure',
44
+ # detail: 'something went terribly wrong',
45
+ # status: '500'
46
+ # }.merge!(errorSource)
47
+ def self.attribute_error_objects(attribute_name, attribute_errors)
48
+ attribute_errors.map do |attribute_error|
49
+ {
50
+ source: error_source(:pointer, attribute_name),
51
+ detail: attribute_error
52
+ }
53
+ end
54
+ end
55
+
56
+ # errorSource
57
+ # description:
58
+ # oneOf
59
+ # ☑ pointer : String
60
+ # ☑ parameter : String
61
+ #
62
+ # description:
63
+ # pointer: A JSON Pointer RFC6901 to the associated entity in the request document e.g. "/data"
64
+ # for a primary data object, or "/data/attributes/title" for a specific attribute.
65
+ # https://tools.ietf.org/html/rfc6901
66
+ #
67
+ # parameter: A string indicating which query parameter caused the error
68
+ # structure:
69
+ # if is_attribute?
70
+ # {
71
+ # pointer: '/data/attributes/red-button'
72
+ # }
73
+ # else
74
+ # {
75
+ # parameter: 'pres'
76
+ # }
77
+ # end
78
+ def self.error_source(source_type, attribute_name)
79
+ case source_type
80
+ when :pointer
81
+ {
82
+ pointer: ActiveModelSerializers::JsonPointer.new(:attribute, attribute_name)
83
+ }
84
+ when :parameter
85
+ {
86
+ parameter: attribute_name
87
+ }
88
+ else
89
+ fail UnknownSourceTypeError, "Unknown source type '#{source_type}' for attribute_name '#{attribute_name}'"
90
+ end
91
+ end
92
+ # rubocop:enable Style/AsciiComments
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,49 @@
1
+ module ActiveModelSerializers
2
+ module Adapter
3
+ class JsonApi < Base
4
+ # {http://jsonapi.org/format/#document-jsonapi-object Jsonapi Object}
5
+
6
+ # toplevel_jsonapi
7
+ # definition:
8
+ # JSON Object
9
+ #
10
+ # properties:
11
+ # version : String
12
+ # meta
13
+ #
14
+ # description:
15
+ # An object describing the server's implementation
16
+ # structure:
17
+ # {
18
+ # version: ActiveModelSerializers.config.jsonapi_version,
19
+ # meta: ActiveModelSerializers.config.jsonapi_toplevel_meta
20
+ # }.reject! { |_, v| v.blank? }
21
+ # prs:
22
+ # https://github.com/rails-api/active_model_serializers/pull/1050
23
+ module Jsonapi
24
+ module_function
25
+
26
+ def add!(hash)
27
+ hash.merge!(object) if include_object?
28
+ end
29
+
30
+ def include_object?
31
+ ActiveModelSerializers.config.jsonapi_include_toplevel_object
32
+ end
33
+
34
+ # TODO: see if we can cache this
35
+ def object
36
+ object = {
37
+ jsonapi: {
38
+ version: ActiveModelSerializers.config.jsonapi_version,
39
+ meta: ActiveModelSerializers.config.jsonapi_toplevel_meta
40
+ }
41
+ }
42
+ object[:jsonapi].reject! { |_, v| v.blank? }
43
+
44
+ object
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,83 @@
1
+ module ActiveModelSerializers
2
+ module Adapter
3
+ class JsonApi
4
+ # link
5
+ # definition:
6
+ # oneOf
7
+ # linkString
8
+ # linkObject
9
+ #
10
+ # description:
11
+ # A link **MUST** be represented as either: a string containing the link's URL or a link
12
+ # object."
13
+ # structure:
14
+ # if href?
15
+ # linkString
16
+ # else
17
+ # linkObject
18
+ # end
19
+ #
20
+ # linkString
21
+ # definition:
22
+ # URI
23
+ #
24
+ # description:
25
+ # A string containing the link's URL.
26
+ # structure:
27
+ # 'http://example.com/link-string'
28
+ #
29
+ # linkObject
30
+ # definition:
31
+ # JSON Object
32
+ #
33
+ # properties:
34
+ # href (required) : URI
35
+ # meta
36
+ # structure:
37
+ # {
38
+ # href: 'http://example.com/link-object',
39
+ # meta: meta,
40
+ # }.reject! {|_,v| v.nil? }
41
+ class Link
42
+ include SerializationContext::UrlHelpers
43
+
44
+ def initialize(serializer, value)
45
+ @_routes ||= nil # handles warning
46
+ # actionpack-4.0.13/lib/action_dispatch/routing/route_set.rb:417: warning: instance variable @_routes not initialized
47
+ @object = serializer.object
48
+ @scope = serializer.scope
49
+ # Use the return value of the block unless it is nil.
50
+ if value.respond_to?(:call)
51
+ @value = instance_eval(&value)
52
+ else
53
+ @value = value
54
+ end
55
+ end
56
+
57
+ def href(value)
58
+ @href = value
59
+ nil
60
+ end
61
+
62
+ def meta(value)
63
+ @meta = value
64
+ nil
65
+ end
66
+
67
+ def as_json
68
+ return @value if @value
69
+
70
+ hash = {}
71
+ hash[:href] = @href if defined?(@href)
72
+ hash[:meta] = @meta if defined?(@meta)
73
+
74
+ hash.any? ? hash : nil
75
+ end
76
+
77
+ protected
78
+
79
+ attr_reader :object, :scope
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,37 @@
1
+ module ActiveModelSerializers
2
+ module Adapter
3
+ class JsonApi
4
+ # meta
5
+ # definition:
6
+ # JSON Object
7
+ #
8
+ # description:
9
+ # Non-standard meta-information that can not be represented as an attribute or relationship.
10
+ # structure:
11
+ # {
12
+ # attitude: 'adjustable'
13
+ # }
14
+ class Meta
15
+ def initialize(serializer)
16
+ @object = serializer.object
17
+ @scope = serializer.scope
18
+
19
+ # Use the return value of the block unless it is nil.
20
+ if serializer._meta.respond_to?(:call)
21
+ @value = instance_eval(&serializer._meta)
22
+ else
23
+ @value = serializer._meta
24
+ end
25
+ end
26
+
27
+ def as_json
28
+ @value
29
+ end
30
+
31
+ protected
32
+
33
+ attr_reader :object, :scope
34
+ end
35
+ end
36
+ end
37
+ end