tiny-max-kit 0.0.1
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.
- checksums.yaml +7 -0
- data/active_model_serializers-0.10.16/CHANGELOG.md +793 -0
- data/active_model_serializers-0.10.16/MIT-LICENSE +22 -0
- data/active_model_serializers-0.10.16/README.md +304 -0
- data/active_model_serializers-0.10.16/lib/action_controller/serialization.rb +76 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializable_resource.rb +13 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/adapter/attributes.rb +17 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/adapter/base.rb +20 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/adapter/json.rb +17 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/adapter/json_api.rb +17 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/adapter/null.rb +17 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/adapter.rb +26 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/array_serializer.rb +14 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/association.rb +73 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/attribute.rb +27 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/belongs_to_reflection.rb +13 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/collection_serializer.rb +99 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/concerns/caching.rb +305 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/error_serializer.rb +16 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/errors_serializer.rb +34 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/field.rb +92 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/fieldset.rb +33 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/has_many_reflection.rb +12 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/has_one_reflection.rb +9 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/lazy_association.rb +99 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/link.rb +23 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/lint.rb +152 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/null.rb +19 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/reflection.rb +212 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer/version.rb +7 -0
- data/active_model_serializers-0.10.16/lib/active_model/serializer.rb +430 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/adapter/attributes.rb +36 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/adapter/base.rb +85 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/adapter/json.rb +23 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/adapter/json_api/deserialization.rb +215 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/adapter/json_api/error.rb +98 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/adapter/json_api/jsonapi.rb +51 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/adapter/json_api/link.rb +85 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/adapter/json_api/meta.rb +39 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/adapter/json_api/pagination_links.rb +94 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/adapter/json_api/relationship.rb +106 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +68 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/adapter/json_api.rb +535 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/adapter/null.rb +11 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/adapter.rb +100 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/callbacks.rb +57 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/deprecate.rb +56 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/deserialization.rb +17 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/json_pointer.rb +16 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/logging.rb +124 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/lookup_chain.rb +82 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/model.rb +132 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/railtie.rb +62 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/register_jsonapi_renderer.rb +80 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/serializable_resource.rb +84 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/serialization_context.rb +41 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/test/schema.rb +140 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/test/serializer.rb +127 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers/test.rb +9 -0
- data/active_model_serializers-0.10.16/lib/active_model_serializers.rb +63 -0
- data/active_model_serializers-0.10.16/lib/generators/rails/USAGE +6 -0
- data/active_model_serializers-0.10.16/lib/generators/rails/resource_override.rb +12 -0
- data/active_model_serializers-0.10.16/lib/generators/rails/serializer_generator.rb +38 -0
- data/active_model_serializers-0.10.16/lib/generators/rails/templates/serializer.rb.erb +8 -0
- data/active_model_serializers-0.10.16/lib/grape/active_model_serializers.rb +18 -0
- data/active_model_serializers-0.10.16/lib/grape/formatters/active_model_serializers.rb +34 -0
- data/active_model_serializers-0.10.16/lib/grape/helpers/active_model_serializers.rb +19 -0
- data/active_model_serializers-0.10.16/lib/tasks/rubocop.rake +60 -0
- data/tiny-max-kit.gemspec +12 -0
- metadata +109 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveModelSerializers
|
|
4
|
+
module Adapter
|
|
5
|
+
class JsonApi
|
|
6
|
+
# NOTE(Experimental):
|
|
7
|
+
# This is an experimental feature. Both the interface and internals could be subject
|
|
8
|
+
# to changes.
|
|
9
|
+
module Deserialization
|
|
10
|
+
InvalidDocument = Class.new(ArgumentError)
|
|
11
|
+
|
|
12
|
+
module_function
|
|
13
|
+
|
|
14
|
+
# Transform a JSON API document, containing a single data object,
|
|
15
|
+
# into a hash that is ready for ActiveRecord::Base.new() and such.
|
|
16
|
+
# Raises InvalidDocument if the payload is not properly formatted.
|
|
17
|
+
#
|
|
18
|
+
# @param [Hash|ActionController::Parameters] document
|
|
19
|
+
# @param [Hash] options
|
|
20
|
+
# only: Array of symbols of whitelisted fields.
|
|
21
|
+
# except: Array of symbols of blacklisted fields.
|
|
22
|
+
# keys: Hash of translated keys (e.g. :author => :user).
|
|
23
|
+
# polymorphic: Array of symbols of polymorphic fields.
|
|
24
|
+
# @return [Hash]
|
|
25
|
+
#
|
|
26
|
+
# @example
|
|
27
|
+
# document = {
|
|
28
|
+
# data: {
|
|
29
|
+
# id: 1,
|
|
30
|
+
# type: 'post',
|
|
31
|
+
# attributes: {
|
|
32
|
+
# title: 'Title 1',
|
|
33
|
+
# date: '2015-12-20'
|
|
34
|
+
# },
|
|
35
|
+
# associations: {
|
|
36
|
+
# author: {
|
|
37
|
+
# data: {
|
|
38
|
+
# type: 'user',
|
|
39
|
+
# id: 2
|
|
40
|
+
# }
|
|
41
|
+
# },
|
|
42
|
+
# second_author: {
|
|
43
|
+
# data: nil
|
|
44
|
+
# },
|
|
45
|
+
# comments: {
|
|
46
|
+
# data: [{
|
|
47
|
+
# type: 'comment',
|
|
48
|
+
# id: 3
|
|
49
|
+
# },{
|
|
50
|
+
# type: 'comment',
|
|
51
|
+
# id: 4
|
|
52
|
+
# }]
|
|
53
|
+
# }
|
|
54
|
+
# }
|
|
55
|
+
# }
|
|
56
|
+
# }
|
|
57
|
+
#
|
|
58
|
+
# parse(document) #=>
|
|
59
|
+
# # {
|
|
60
|
+
# # title: 'Title 1',
|
|
61
|
+
# # date: '2015-12-20',
|
|
62
|
+
# # author_id: 2,
|
|
63
|
+
# # second_author_id: nil
|
|
64
|
+
# # comment_ids: [3, 4]
|
|
65
|
+
# # }
|
|
66
|
+
#
|
|
67
|
+
# parse(document, only: [:title, :date, :author],
|
|
68
|
+
# keys: { date: :published_at },
|
|
69
|
+
# polymorphic: [:author]) #=>
|
|
70
|
+
# # {
|
|
71
|
+
# # title: 'Title 1',
|
|
72
|
+
# # published_at: '2015-12-20',
|
|
73
|
+
# # author_id: '2',
|
|
74
|
+
# # author_type: 'people'
|
|
75
|
+
# # }
|
|
76
|
+
#
|
|
77
|
+
def parse!(document, options = {})
|
|
78
|
+
parse(document, options) do |invalid_payload, reason|
|
|
79
|
+
fail InvalidDocument, "Invalid payload (#{reason}): #{invalid_payload}"
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Same as parse!, but returns an empty hash instead of raising InvalidDocument
|
|
84
|
+
# on invalid payloads.
|
|
85
|
+
def parse(document, options = {})
|
|
86
|
+
document = document.dup.permit!.to_h if document.is_a?(ActionController::Parameters)
|
|
87
|
+
|
|
88
|
+
validate_payload(document) do |invalid_document, reason|
|
|
89
|
+
yield invalid_document, reason if block_given?
|
|
90
|
+
return {}
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
primary_data = document['data']
|
|
94
|
+
attributes = primary_data['attributes'] || {}
|
|
95
|
+
attributes['id'] = primary_data['id'] if primary_data['id']
|
|
96
|
+
relationships = primary_data['relationships'] || {}
|
|
97
|
+
|
|
98
|
+
filter_fields(attributes, options)
|
|
99
|
+
filter_fields(relationships, options)
|
|
100
|
+
|
|
101
|
+
hash = {}
|
|
102
|
+
hash.merge!(parse_attributes(attributes, options))
|
|
103
|
+
hash.merge!(parse_relationships(relationships, options))
|
|
104
|
+
|
|
105
|
+
hash
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Checks whether a payload is compliant with the JSON API spec.
|
|
109
|
+
#
|
|
110
|
+
# @api private
|
|
111
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
112
|
+
def validate_payload(payload)
|
|
113
|
+
unless payload.is_a?(Hash)
|
|
114
|
+
yield payload, 'Expected hash'
|
|
115
|
+
return
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
primary_data = payload['data']
|
|
119
|
+
unless primary_data.is_a?(Hash)
|
|
120
|
+
yield payload, { data: 'Expected hash' }
|
|
121
|
+
return
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
attributes = primary_data['attributes'] || {}
|
|
125
|
+
unless attributes.is_a?(Hash)
|
|
126
|
+
yield payload, { data: { attributes: 'Expected hash or nil' } }
|
|
127
|
+
return
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
relationships = primary_data['relationships'] || {}
|
|
131
|
+
unless relationships.is_a?(Hash)
|
|
132
|
+
yield payload, { data: { relationships: 'Expected hash or nil' } }
|
|
133
|
+
return
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
relationships.each do |(key, value)|
|
|
137
|
+
unless value.is_a?(Hash) && value.key?('data')
|
|
138
|
+
yield payload, { data: { relationships: { key => 'Expected hash with :data key' } } }
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
143
|
+
|
|
144
|
+
# @api private
|
|
145
|
+
def filter_fields(fields, options)
|
|
146
|
+
if (only = options[:only])
|
|
147
|
+
fields.slice!(*Array(only).map(&:to_s))
|
|
148
|
+
elsif (except = options[:except])
|
|
149
|
+
fields.except!(*Array(except).map(&:to_s))
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# @api private
|
|
154
|
+
def field_key(field, options)
|
|
155
|
+
(options[:keys] || {}).fetch(field.to_sym, field).to_sym
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# @api private
|
|
159
|
+
def parse_attributes(attributes, options)
|
|
160
|
+
transform_keys(attributes, options)
|
|
161
|
+
.map { |(k, v)| { field_key(k, options) => v } }
|
|
162
|
+
.reduce({}, :merge)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Given an association name, and a relationship data attribute, build a hash
|
|
166
|
+
# mapping the corresponding ActiveRecord attribute to the corresponding value.
|
|
167
|
+
#
|
|
168
|
+
# @example
|
|
169
|
+
# parse_relationship(:comments, [{ 'id' => '1', 'type' => 'comments' },
|
|
170
|
+
# { 'id' => '2', 'type' => 'comments' }],
|
|
171
|
+
# {})
|
|
172
|
+
# # => { :comment_ids => ['1', '2'] }
|
|
173
|
+
# parse_relationship(:author, { 'id' => '1', 'type' => 'users' }, {})
|
|
174
|
+
# # => { :author_id => '1' }
|
|
175
|
+
# parse_relationship(:author, nil, {})
|
|
176
|
+
# # => { :author_id => nil }
|
|
177
|
+
# @param [Symbol] assoc_name
|
|
178
|
+
# @param [Hash] assoc_data
|
|
179
|
+
# @param [Hash] options
|
|
180
|
+
# @return [Hash{Symbol, Object}]
|
|
181
|
+
#
|
|
182
|
+
# @api private
|
|
183
|
+
def parse_relationship(assoc_name, assoc_data, options)
|
|
184
|
+
prefix_key = field_key(assoc_name, options).to_s.singularize
|
|
185
|
+
hash =
|
|
186
|
+
if assoc_data.is_a?(Array)
|
|
187
|
+
{ "#{prefix_key}_ids".to_sym => assoc_data.map { |ri| ri['id'] } }
|
|
188
|
+
else
|
|
189
|
+
{ "#{prefix_key}_id".to_sym => assoc_data ? assoc_data['id'] : nil }
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
polymorphic = (options[:polymorphic] || []).include?(assoc_name.to_sym)
|
|
193
|
+
if polymorphic
|
|
194
|
+
hash["#{prefix_key}_type".to_sym] = assoc_data.present? ? assoc_data['type'].classify : nil
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
hash
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# @api private
|
|
201
|
+
def parse_relationships(relationships, options)
|
|
202
|
+
transform_keys(relationships, options)
|
|
203
|
+
.map { |(k, v)| parse_relationship(k, v['data'], options) }
|
|
204
|
+
.reduce({}, :merge)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# @api private
|
|
208
|
+
def transform_keys(hash, options)
|
|
209
|
+
transform = options[:key_transform] || :underscore
|
|
210
|
+
CaseTransform.send(transform, hash)
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveModelSerializers
|
|
4
|
+
module Adapter
|
|
5
|
+
class JsonApi < Base
|
|
6
|
+
module Error
|
|
7
|
+
# rubocop:disable Style/AsciiComments
|
|
8
|
+
UnknownSourceTypeError = Class.new(ArgumentError)
|
|
9
|
+
|
|
10
|
+
# Builds a JSON API Errors Object
|
|
11
|
+
# {http://jsonapi.org/format/#errors JSON API Errors}
|
|
12
|
+
#
|
|
13
|
+
# @param [ActiveModel::Serializer::ErrorSerializer] error_serializer
|
|
14
|
+
# @return [Array<Symbol, Array<String>>] i.e. attribute_name, [attribute_errors]
|
|
15
|
+
def self.resource_errors(error_serializer, options)
|
|
16
|
+
error_serializer.as_json.flat_map do |attribute_name, attribute_errors|
|
|
17
|
+
attribute_name = JsonApi.send(:transform_key_casing!, attribute_name,
|
|
18
|
+
options)
|
|
19
|
+
attribute_error_objects(attribute_name, attribute_errors)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# definition:
|
|
24
|
+
# JSON Object
|
|
25
|
+
#
|
|
26
|
+
# properties:
|
|
27
|
+
# ☐ id : String
|
|
28
|
+
# ☐ status : String
|
|
29
|
+
# ☐ code : String
|
|
30
|
+
# ☐ title : String
|
|
31
|
+
# ☑ detail : String
|
|
32
|
+
# ☐ links
|
|
33
|
+
# ☐ meta
|
|
34
|
+
# ☑ error_source
|
|
35
|
+
#
|
|
36
|
+
# description:
|
|
37
|
+
# id : A unique identifier for this particular occurrence of the problem.
|
|
38
|
+
# status : The HTTP status code applicable to this problem, expressed as a string value
|
|
39
|
+
# code : An application-specific error code, expressed as a string value.
|
|
40
|
+
# title : A short, human-readable summary of the problem. It **SHOULD NOT** change from
|
|
41
|
+
# occurrence to occurrence of the problem, except for purposes of localization.
|
|
42
|
+
# detail : A human-readable explanation specific to this occurrence of the problem.
|
|
43
|
+
# structure:
|
|
44
|
+
# {
|
|
45
|
+
# title: 'SystemFailure',
|
|
46
|
+
# detail: 'something went terribly wrong',
|
|
47
|
+
# status: '500'
|
|
48
|
+
# }.merge!(errorSource)
|
|
49
|
+
def self.attribute_error_objects(attribute_name, attribute_errors)
|
|
50
|
+
attribute_errors.map do |attribute_error|
|
|
51
|
+
{
|
|
52
|
+
source: error_source(:pointer, attribute_name),
|
|
53
|
+
detail: attribute_error
|
|
54
|
+
}
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# errorSource
|
|
59
|
+
# description:
|
|
60
|
+
# oneOf
|
|
61
|
+
# ☑ pointer : String
|
|
62
|
+
# ☑ parameter : String
|
|
63
|
+
#
|
|
64
|
+
# description:
|
|
65
|
+
# pointer: A JSON Pointer RFC6901 to the associated entity in the request document e.g. "/data"
|
|
66
|
+
# for a primary data object, or "/data/attributes/title" for a specific attribute.
|
|
67
|
+
# https://tools.ietf.org/html/rfc6901
|
|
68
|
+
#
|
|
69
|
+
# parameter: A string indicating which query parameter caused the error
|
|
70
|
+
# structure:
|
|
71
|
+
# if is_attribute?
|
|
72
|
+
# {
|
|
73
|
+
# pointer: '/data/attributes/red-button'
|
|
74
|
+
# }
|
|
75
|
+
# else
|
|
76
|
+
# {
|
|
77
|
+
# parameter: 'pres'
|
|
78
|
+
# }
|
|
79
|
+
# end
|
|
80
|
+
def self.error_source(source_type, attribute_name)
|
|
81
|
+
case source_type
|
|
82
|
+
when :pointer
|
|
83
|
+
{
|
|
84
|
+
pointer: ActiveModelSerializers::JsonPointer.new(:attribute, attribute_name)
|
|
85
|
+
}
|
|
86
|
+
when :parameter
|
|
87
|
+
{
|
|
88
|
+
parameter: attribute_name
|
|
89
|
+
}
|
|
90
|
+
else
|
|
91
|
+
fail UnknownSourceTypeError, "Unknown source type '#{source_type}' for attribute_name '#{attribute_name}'"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
# rubocop:enable Style/AsciiComments
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
data/active_model_serializers-0.10.16/lib/active_model_serializers/adapter/json_api/jsonapi.rb
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveModelSerializers
|
|
4
|
+
module Adapter
|
|
5
|
+
class JsonApi < Base
|
|
6
|
+
# {http://jsonapi.org/format/#document-jsonapi-object Jsonapi Object}
|
|
7
|
+
|
|
8
|
+
# toplevel_jsonapi
|
|
9
|
+
# definition:
|
|
10
|
+
# JSON Object
|
|
11
|
+
#
|
|
12
|
+
# properties:
|
|
13
|
+
# version : String
|
|
14
|
+
# meta
|
|
15
|
+
#
|
|
16
|
+
# description:
|
|
17
|
+
# An object describing the server's implementation
|
|
18
|
+
# structure:
|
|
19
|
+
# {
|
|
20
|
+
# version: ActiveModelSerializers.config.jsonapi_version,
|
|
21
|
+
# meta: ActiveModelSerializers.config.jsonapi_toplevel_meta
|
|
22
|
+
# }.reject! { |_, v| v.blank? }
|
|
23
|
+
# prs:
|
|
24
|
+
# https://github.com/rails-api/active_model_serializers/pull/1050
|
|
25
|
+
module Jsonapi
|
|
26
|
+
module_function
|
|
27
|
+
|
|
28
|
+
def add!(hash)
|
|
29
|
+
hash.merge!(object) if include_object?
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def include_object?
|
|
33
|
+
ActiveModelSerializers.config.jsonapi_include_toplevel_object
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# TODO: see if we can cache this
|
|
37
|
+
def object
|
|
38
|
+
object = {
|
|
39
|
+
jsonapi: {
|
|
40
|
+
version: ActiveModelSerializers.config.jsonapi_version,
|
|
41
|
+
meta: ActiveModelSerializers.config.jsonapi_toplevel_meta
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
object[:jsonapi].reject! { |_, v| v.blank? }
|
|
45
|
+
|
|
46
|
+
object
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveModelSerializers
|
|
4
|
+
module Adapter
|
|
5
|
+
class JsonApi
|
|
6
|
+
# link
|
|
7
|
+
# definition:
|
|
8
|
+
# oneOf
|
|
9
|
+
# linkString
|
|
10
|
+
# linkObject
|
|
11
|
+
#
|
|
12
|
+
# description:
|
|
13
|
+
# A link **MUST** be represented as either: a string containing the link's URL or a link
|
|
14
|
+
# object."
|
|
15
|
+
# structure:
|
|
16
|
+
# if href?
|
|
17
|
+
# linkString
|
|
18
|
+
# else
|
|
19
|
+
# linkObject
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# linkString
|
|
23
|
+
# definition:
|
|
24
|
+
# URI
|
|
25
|
+
#
|
|
26
|
+
# description:
|
|
27
|
+
# A string containing the link's URL.
|
|
28
|
+
# structure:
|
|
29
|
+
# 'http://example.com/link-string'
|
|
30
|
+
#
|
|
31
|
+
# linkObject
|
|
32
|
+
# definition:
|
|
33
|
+
# JSON Object
|
|
34
|
+
#
|
|
35
|
+
# properties:
|
|
36
|
+
# href (required) : URI
|
|
37
|
+
# meta
|
|
38
|
+
# structure:
|
|
39
|
+
# {
|
|
40
|
+
# href: 'http://example.com/link-object',
|
|
41
|
+
# meta: meta,
|
|
42
|
+
# }.reject! {|_,v| v.nil? }
|
|
43
|
+
class Link
|
|
44
|
+
include SerializationContext::UrlHelpers
|
|
45
|
+
|
|
46
|
+
def initialize(serializer, value)
|
|
47
|
+
@_routes ||= nil # handles warning
|
|
48
|
+
# actionpack-4.0.13/lib/action_dispatch/routing/route_set.rb:417: warning: instance variable @_routes not initialized
|
|
49
|
+
@object = serializer.object
|
|
50
|
+
@scope = serializer.scope
|
|
51
|
+
# Use the return value of the block unless it is nil.
|
|
52
|
+
if value.respond_to?(:call)
|
|
53
|
+
@value = instance_eval(&value)
|
|
54
|
+
else
|
|
55
|
+
@value = value
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def href(value)
|
|
60
|
+
@href = value
|
|
61
|
+
nil
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def meta(value)
|
|
65
|
+
@meta = value
|
|
66
|
+
nil
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def as_json
|
|
70
|
+
return @value if @value
|
|
71
|
+
|
|
72
|
+
hash = {}
|
|
73
|
+
hash[:href] = @href if defined?(@href)
|
|
74
|
+
hash[:meta] = @meta if defined?(@meta)
|
|
75
|
+
|
|
76
|
+
hash.any? ? hash : nil
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
protected
|
|
80
|
+
|
|
81
|
+
attr_reader :object, :scope
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveModelSerializers
|
|
4
|
+
module Adapter
|
|
5
|
+
class JsonApi
|
|
6
|
+
# meta
|
|
7
|
+
# definition:
|
|
8
|
+
# JSON Object
|
|
9
|
+
#
|
|
10
|
+
# description:
|
|
11
|
+
# Non-standard meta-information that can not be represented as an attribute or relationship.
|
|
12
|
+
# structure:
|
|
13
|
+
# {
|
|
14
|
+
# attitude: 'adjustable'
|
|
15
|
+
# }
|
|
16
|
+
class Meta
|
|
17
|
+
def initialize(serializer)
|
|
18
|
+
@object = serializer.object
|
|
19
|
+
@scope = serializer.scope
|
|
20
|
+
|
|
21
|
+
# Use the return value of the block unless it is nil.
|
|
22
|
+
if serializer._meta.respond_to?(:call)
|
|
23
|
+
@value = instance_eval(&serializer._meta)
|
|
24
|
+
else
|
|
25
|
+
@value = serializer._meta
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def as_json
|
|
30
|
+
@value
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
protected
|
|
34
|
+
|
|
35
|
+
attr_reader :object, :scope
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveModelSerializers
|
|
4
|
+
module Adapter
|
|
5
|
+
class JsonApi < Base
|
|
6
|
+
class PaginationLinks
|
|
7
|
+
MissingSerializationContextError = Class.new(KeyError)
|
|
8
|
+
FIRST_PAGE = 1
|
|
9
|
+
|
|
10
|
+
attr_reader :collection, :context
|
|
11
|
+
|
|
12
|
+
def initialize(collection, adapter_options)
|
|
13
|
+
@collection = collection
|
|
14
|
+
@adapter_options = adapter_options
|
|
15
|
+
@context = adapter_options.fetch(:serialization_context) do
|
|
16
|
+
fail MissingSerializationContextError, <<-EOF.freeze
|
|
17
|
+
JsonApi::PaginationLinks requires a ActiveModelSerializers::SerializationContext.
|
|
18
|
+
Please pass a ':serialization_context' option or
|
|
19
|
+
override CollectionSerializer#paginated? to return 'false'.
|
|
20
|
+
EOF
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def as_json
|
|
25
|
+
{
|
|
26
|
+
self: location_url,
|
|
27
|
+
first: first_page_url,
|
|
28
|
+
prev: prev_page_url,
|
|
29
|
+
next: next_page_url,
|
|
30
|
+
last: last_page_url
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
protected
|
|
35
|
+
|
|
36
|
+
attr_reader :adapter_options
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def location_url
|
|
41
|
+
url_for_page(collection.current_page)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def first_page_url
|
|
45
|
+
url_for_page(1)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def last_page_url
|
|
49
|
+
if collection.total_pages == 0
|
|
50
|
+
url_for_page(FIRST_PAGE)
|
|
51
|
+
else
|
|
52
|
+
url_for_page(collection.total_pages)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def prev_page_url
|
|
57
|
+
return nil if collection.current_page == FIRST_PAGE
|
|
58
|
+
if collection.current_page > collection.total_pages
|
|
59
|
+
return url_for_page(collection.total_pages)
|
|
60
|
+
end
|
|
61
|
+
url_for_page(collection.current_page - FIRST_PAGE)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def next_page_url
|
|
65
|
+
return nil if collection.total_pages == 0 ||
|
|
66
|
+
collection.current_page >= collection.total_pages
|
|
67
|
+
url_for_page(collection.next_page)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def url_for_page(number)
|
|
71
|
+
params = query_parameters.dup
|
|
72
|
+
params[:page] = { size: per_page, number: number }
|
|
73
|
+
"#{url(adapter_options)}?#{params.to_query}"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def url(options = {})
|
|
77
|
+
@url ||= options.fetch(:links, {}).fetch(:self, nil) || request_url
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def request_url
|
|
81
|
+
@request_url ||= context.request_url
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def query_parameters
|
|
85
|
+
@query_parameters ||= context.query_parameters
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def per_page
|
|
89
|
+
@per_page ||= collection.try(:per_page) || collection.try(:limit_value) || collection.size
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
data/active_model_serializers-0.10.16/lib/active_model_serializers/adapter/json_api/relationship.rb
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveModelSerializers
|
|
4
|
+
module Adapter
|
|
5
|
+
class JsonApi
|
|
6
|
+
class Relationship
|
|
7
|
+
# {http://jsonapi.org/format/#document-resource-object-related-resource-links Document Resource Object Related Resource Links}
|
|
8
|
+
# {http://jsonapi.org/format/#document-links Document Links}
|
|
9
|
+
# {http://jsonapi.org/format/#document-resource-object-linkage Document Resource Relationship Linkage}
|
|
10
|
+
# {http://jsonapi.org/format/#document-meta Document Meta}
|
|
11
|
+
def initialize(parent_serializer, serializable_resource_options, association)
|
|
12
|
+
@parent_serializer = parent_serializer
|
|
13
|
+
@association = association
|
|
14
|
+
@serializable_resource_options = serializable_resource_options
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def as_json
|
|
18
|
+
hash = {}
|
|
19
|
+
|
|
20
|
+
hash[:data] = data_for(association) if association.include_data?
|
|
21
|
+
|
|
22
|
+
links = links_for(association)
|
|
23
|
+
hash[:links] = links if links.any?
|
|
24
|
+
|
|
25
|
+
meta = meta_for(association)
|
|
26
|
+
hash[:meta] = meta if meta
|
|
27
|
+
hash[:meta] = {} if hash.empty?
|
|
28
|
+
|
|
29
|
+
hash
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
protected
|
|
33
|
+
|
|
34
|
+
attr_reader :parent_serializer, :serializable_resource_options, :association
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
# TODO(BF): Avoid db hit on belong_to_ releationship by using foreign_key on self
|
|
39
|
+
def data_for(association)
|
|
40
|
+
if association.collection?
|
|
41
|
+
data_for_many(association)
|
|
42
|
+
else
|
|
43
|
+
data_for_one(association)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def data_for_one(association)
|
|
48
|
+
if belongs_to_id_on_self?(association)
|
|
49
|
+
id = parent_serializer.read_attribute_for_serialization(association.reflection.foreign_key)
|
|
50
|
+
type =
|
|
51
|
+
if association.polymorphic?
|
|
52
|
+
# We can't infer resource type for polymorphic relationships from the serializer.
|
|
53
|
+
# We can ONLY know a polymorphic resource type by inspecting each resource.
|
|
54
|
+
association.lazy_association.serializer.json_key
|
|
55
|
+
else
|
|
56
|
+
association.reflection.type.to_s
|
|
57
|
+
end
|
|
58
|
+
ResourceIdentifier.for_type_with_id(type, id, serializable_resource_options)
|
|
59
|
+
else
|
|
60
|
+
# TODO(BF): Process relationship without evaluating lazy_association
|
|
61
|
+
serializer = association.lazy_association.serializer
|
|
62
|
+
if (virtual_value = association.virtual_value)
|
|
63
|
+
virtual_value
|
|
64
|
+
elsif serializer && association.object
|
|
65
|
+
ResourceIdentifier.new(serializer, serializable_resource_options).as_json
|
|
66
|
+
else
|
|
67
|
+
nil
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def data_for_many(association)
|
|
73
|
+
# TODO(BF): Process relationship without evaluating lazy_association
|
|
74
|
+
collection_serializer = association.lazy_association.serializer
|
|
75
|
+
if collection_serializer.respond_to?(:each)
|
|
76
|
+
collection_serializer.map do |serializer|
|
|
77
|
+
ResourceIdentifier.new(serializer, serializable_resource_options).as_json
|
|
78
|
+
end
|
|
79
|
+
elsif (virtual_value = association.virtual_value)
|
|
80
|
+
virtual_value
|
|
81
|
+
else
|
|
82
|
+
[]
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def links_for(association)
|
|
87
|
+
association.links.each_with_object({}) do |(key, value), hash|
|
|
88
|
+
result = Link.new(parent_serializer, value).as_json
|
|
89
|
+
hash[key] = result if result
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def meta_for(association)
|
|
94
|
+
meta = association.meta
|
|
95
|
+
meta.respond_to?(:call) ? parent_serializer.instance_eval(&meta) : meta
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def belongs_to_id_on_self?(association)
|
|
99
|
+
parent_serializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship &&
|
|
100
|
+
association.belongs_to? &&
|
|
101
|
+
parent_serializer.object.respond_to?(association.reflection.foreign_key)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|