jsonapi_compliable 0.11.34 → 1.0.alpha.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.ruby-version +1 -1
- data/.travis.yml +1 -2
- data/Rakefile +7 -3
- data/jsonapi_compliable.gemspec +7 -3
- data/lib/generators/jsonapi/resource_generator.rb +8 -79
- data/lib/generators/jsonapi/templates/application_resource.rb.erb +2 -1
- data/lib/generators/jsonapi/templates/controller.rb.erb +19 -64
- data/lib/generators/jsonapi/templates/resource.rb.erb +5 -47
- data/lib/generators/jsonapi/templates/resource_reads_spec.rb.erb +62 -0
- data/lib/generators/jsonapi/templates/resource_writes_spec.rb.erb +63 -0
- data/lib/jsonapi_compliable.rb +87 -18
- data/lib/jsonapi_compliable/adapters/abstract.rb +202 -45
- data/lib/jsonapi_compliable/adapters/active_record.rb +6 -130
- data/lib/jsonapi_compliable/adapters/active_record/base.rb +247 -0
- data/lib/jsonapi_compliable/adapters/active_record/belongs_to_sideload.rb +17 -0
- data/lib/jsonapi_compliable/adapters/active_record/has_many_sideload.rb +17 -0
- data/lib/jsonapi_compliable/adapters/active_record/has_one_sideload.rb +17 -0
- data/lib/jsonapi_compliable/adapters/active_record/inferrence.rb +12 -0
- data/lib/jsonapi_compliable/adapters/active_record/many_to_many_sideload.rb +30 -0
- data/lib/jsonapi_compliable/adapters/null.rb +177 -6
- data/lib/jsonapi_compliable/base.rb +33 -320
- data/lib/jsonapi_compliable/context.rb +16 -0
- data/lib/jsonapi_compliable/deserializer.rb +14 -39
- data/lib/jsonapi_compliable/errors.rb +227 -24
- data/lib/jsonapi_compliable/extensions/extra_attribute.rb +3 -1
- data/lib/jsonapi_compliable/filter_operators.rb +25 -0
- data/lib/jsonapi_compliable/hash_renderer.rb +57 -0
- data/lib/jsonapi_compliable/query.rb +190 -202
- data/lib/jsonapi_compliable/rails.rb +12 -6
- data/lib/jsonapi_compliable/railtie.rb +64 -0
- data/lib/jsonapi_compliable/renderer.rb +60 -0
- data/lib/jsonapi_compliable/resource.rb +35 -663
- data/lib/jsonapi_compliable/resource/configuration.rb +239 -0
- data/lib/jsonapi_compliable/resource/dsl.rb +138 -0
- data/lib/jsonapi_compliable/resource/interface.rb +32 -0
- data/lib/jsonapi_compliable/resource/polymorphism.rb +68 -0
- data/lib/jsonapi_compliable/resource/sideloading.rb +102 -0
- data/lib/jsonapi_compliable/resource_proxy.rb +127 -0
- data/lib/jsonapi_compliable/responders.rb +19 -0
- data/lib/jsonapi_compliable/runner.rb +25 -0
- data/lib/jsonapi_compliable/scope.rb +37 -79
- data/lib/jsonapi_compliable/scoping/extra_attributes.rb +29 -0
- data/lib/jsonapi_compliable/scoping/filter.rb +39 -58
- data/lib/jsonapi_compliable/scoping/filterable.rb +9 -14
- data/lib/jsonapi_compliable/scoping/paginate.rb +9 -3
- data/lib/jsonapi_compliable/scoping/sort.rb +16 -4
- data/lib/jsonapi_compliable/sideload.rb +221 -347
- data/lib/jsonapi_compliable/sideload/belongs_to.rb +34 -0
- data/lib/jsonapi_compliable/sideload/has_many.rb +16 -0
- data/lib/jsonapi_compliable/sideload/has_one.rb +9 -0
- data/lib/jsonapi_compliable/sideload/many_to_many.rb +24 -0
- data/lib/jsonapi_compliable/sideload/polymorphic_belongs_to.rb +108 -0
- data/lib/jsonapi_compliable/stats/payload.rb +4 -8
- data/lib/jsonapi_compliable/types.rb +172 -0
- data/lib/jsonapi_compliable/util/attribute_check.rb +88 -0
- data/lib/jsonapi_compliable/util/persistence.rb +29 -7
- data/lib/jsonapi_compliable/util/relationship_payload.rb +4 -4
- data/lib/jsonapi_compliable/util/render_options.rb +4 -32
- data/lib/jsonapi_compliable/util/serializer_attributes.rb +98 -0
- data/lib/jsonapi_compliable/util/validation_response.rb +15 -9
- data/lib/jsonapi_compliable/version.rb +1 -1
- metadata +105 -24
- data/lib/generators/jsonapi/field_generator.rb +0 -0
- data/lib/generators/jsonapi/templates/create_request_spec.rb.erb +0 -29
- data/lib/generators/jsonapi/templates/destroy_request_spec.rb.erb +0 -20
- data/lib/generators/jsonapi/templates/index_request_spec.rb.erb +0 -22
- data/lib/generators/jsonapi/templates/payload.rb.erb +0 -39
- data/lib/generators/jsonapi/templates/serializer.rb.erb +0 -25
- data/lib/generators/jsonapi/templates/show_request_spec.rb.erb +0 -19
- data/lib/generators/jsonapi/templates/update_request_spec.rb.erb +0 -33
- data/lib/jsonapi_compliable/adapters/active_record_sideloading.rb +0 -152
- data/lib/jsonapi_compliable/scoping/extra_fields.rb +0 -58
@@ -0,0 +1,30 @@
|
|
1
|
+
module JsonapiCompliable
|
2
|
+
module Adapters
|
3
|
+
module ActiveRecord
|
4
|
+
class ManyToManySideload < Sideload::ManyToMany
|
5
|
+
def default_base_scope
|
6
|
+
resource_class.model.all
|
7
|
+
end
|
8
|
+
|
9
|
+
def through_table_name
|
10
|
+
@through_table_name ||= parent_resource_class.model
|
11
|
+
.reflections[through.to_s].klass.table_name
|
12
|
+
end
|
13
|
+
|
14
|
+
def scope(parent_ids)
|
15
|
+
base_scope
|
16
|
+
.includes(through)
|
17
|
+
.where(through_table_name => { true_foreign_key => parent_ids })
|
18
|
+
.distinct
|
19
|
+
end
|
20
|
+
|
21
|
+
def infer_foreign_key
|
22
|
+
parent_model = parent_resource_class.model
|
23
|
+
key = parent_model.reflections[name.to_s].options[:through]
|
24
|
+
value = parent_model.reflections[key.to_s].foreign_key.to_sym
|
25
|
+
{ key => value }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -4,11 +4,186 @@ module JsonapiCompliable
|
|
4
4
|
# Useful when your customization does not support all possible
|
5
5
|
# configuration (e.g. the service you hit does not support sorting)
|
6
6
|
class Null < Abstract
|
7
|
-
|
8
|
-
def filter(scope, attribute, value)
|
7
|
+
def filter_string_eq(scope, attribute, value)
|
9
8
|
scope
|
10
9
|
end
|
11
10
|
|
11
|
+
def filter_string_eql(scope, attribute, value)
|
12
|
+
scope
|
13
|
+
end
|
14
|
+
|
15
|
+
def filter_string_not_eq(scope, attribute, value)
|
16
|
+
scope
|
17
|
+
end
|
18
|
+
|
19
|
+
def filter_string_not_eql(scope, attribute, value)
|
20
|
+
scope
|
21
|
+
end
|
22
|
+
|
23
|
+
def filter_string_prefix_eq(scope, attribute, value)
|
24
|
+
scope
|
25
|
+
end
|
26
|
+
|
27
|
+
def filter_string_not_prefix_eq(scope, attribute, value)
|
28
|
+
scope
|
29
|
+
end
|
30
|
+
|
31
|
+
def filter_string_suffix_eq(scope, attribute, value)
|
32
|
+
scope
|
33
|
+
end
|
34
|
+
|
35
|
+
def filter_string_not_suffix_eq(scope, attribute, value)
|
36
|
+
scope
|
37
|
+
end
|
38
|
+
|
39
|
+
def filter_string_like_eq(scope, attribute, value)
|
40
|
+
scope
|
41
|
+
end
|
42
|
+
|
43
|
+
def filter_string_not_like_eq(scope, attribute, value)
|
44
|
+
scope
|
45
|
+
end
|
46
|
+
|
47
|
+
def filter_integer_eq(scope, attribute, value)
|
48
|
+
scope
|
49
|
+
end
|
50
|
+
|
51
|
+
def filter_integer_not_eq(scope, attribute, value)
|
52
|
+
scope
|
53
|
+
end
|
54
|
+
|
55
|
+
def filter_integer_gt(scope, attribute, value)
|
56
|
+
scope
|
57
|
+
end
|
58
|
+
|
59
|
+
def filter_integer_gte(scope, attribute, value)
|
60
|
+
scope
|
61
|
+
end
|
62
|
+
|
63
|
+
def filter_integer_lt(scope, attribute, value)
|
64
|
+
scope
|
65
|
+
end
|
66
|
+
|
67
|
+
def filter_integer_lte(scope, attribute, value)
|
68
|
+
scope
|
69
|
+
end
|
70
|
+
|
71
|
+
def filter_datetime_eq(scope, attribute, value)
|
72
|
+
scope
|
73
|
+
end
|
74
|
+
|
75
|
+
def filter_datetime_not_eq(scope, attribute, value)
|
76
|
+
scope
|
77
|
+
end
|
78
|
+
|
79
|
+
def filter_datetime_lte(scope, attribute, value)
|
80
|
+
scope
|
81
|
+
end
|
82
|
+
|
83
|
+
def filter_float_eq(scope, attribute, value)
|
84
|
+
scope
|
85
|
+
end
|
86
|
+
|
87
|
+
def filter_float_not_eq(scope, attribute, value)
|
88
|
+
scope
|
89
|
+
end
|
90
|
+
|
91
|
+
def filter_float_gt(scope, attribute, value)
|
92
|
+
scope
|
93
|
+
end
|
94
|
+
|
95
|
+
def filter_float_gte(scope, attribute, value)
|
96
|
+
scope
|
97
|
+
end
|
98
|
+
|
99
|
+
def filter_float_lt(scope, attribute, value)
|
100
|
+
scope
|
101
|
+
end
|
102
|
+
|
103
|
+
def filter_float_lte(scope, attribute, value)
|
104
|
+
scope
|
105
|
+
end
|
106
|
+
|
107
|
+
def filter_decimal_eq(scope, attribute, value)
|
108
|
+
scope
|
109
|
+
end
|
110
|
+
|
111
|
+
def filter_decimal_not_eq(scope, attribute, value)
|
112
|
+
scope
|
113
|
+
end
|
114
|
+
|
115
|
+
def filter_decimal_gt(scope, attribute, value)
|
116
|
+
scope
|
117
|
+
end
|
118
|
+
|
119
|
+
def filter_decimal_gte(scope, attribute, value)
|
120
|
+
scope
|
121
|
+
end
|
122
|
+
|
123
|
+
def filter_decimal_lt(scope, attribute, value)
|
124
|
+
scope
|
125
|
+
end
|
126
|
+
|
127
|
+
def filter_decimal_lte(scope, attribute, value)
|
128
|
+
scope
|
129
|
+
end
|
130
|
+
|
131
|
+
def filter_datetime_eq(scope, attribute, value)
|
132
|
+
scope
|
133
|
+
end
|
134
|
+
|
135
|
+
def filter_datetime_not_eq(scope, attribute, value)
|
136
|
+
scope
|
137
|
+
end
|
138
|
+
|
139
|
+
def filter_datetime_gt(scope, attribute, value)
|
140
|
+
scope
|
141
|
+
end
|
142
|
+
|
143
|
+
def filter_datetime_gte(scope, attribute, value)
|
144
|
+
scope
|
145
|
+
end
|
146
|
+
|
147
|
+
def filter_datetime_lt(scope, attribute, value)
|
148
|
+
scope
|
149
|
+
end
|
150
|
+
|
151
|
+
def filter_datetime_lte(scope, attribute, value)
|
152
|
+
scope
|
153
|
+
end
|
154
|
+
|
155
|
+
def filter_date_eq(scope, attribute, value)
|
156
|
+
scope
|
157
|
+
end
|
158
|
+
|
159
|
+
def filter_date_not_eq(scope, attribute, value)
|
160
|
+
scope
|
161
|
+
end
|
162
|
+
|
163
|
+
def filter_date_gt(scope, attribute, value)
|
164
|
+
scope
|
165
|
+
end
|
166
|
+
|
167
|
+
def filter_date_gte(scope, attribute, value)
|
168
|
+
scope
|
169
|
+
end
|
170
|
+
|
171
|
+
def filter_date_lt(scope, attribute, value)
|
172
|
+
scope
|
173
|
+
end
|
174
|
+
|
175
|
+
def filter_date_lte(scope, attribute, value)
|
176
|
+
scope
|
177
|
+
end
|
178
|
+
|
179
|
+
def filter_boolean_eq(scope, attribute, value)
|
180
|
+
scope
|
181
|
+
end
|
182
|
+
|
183
|
+
def base_scope(model)
|
184
|
+
raise 'Null adapter has no base scope!'
|
185
|
+
end
|
186
|
+
|
12
187
|
# (see Adapters::Abstract#order)
|
13
188
|
def order(scope, attribute, direction)
|
14
189
|
scope
|
@@ -56,10 +231,6 @@ module JsonapiCompliable
|
|
56
231
|
def resolve(scope)
|
57
232
|
scope
|
58
233
|
end
|
59
|
-
|
60
|
-
# (see Adapters::Abstract#associate)
|
61
|
-
def associate(parent, child, association_name, association_type)
|
62
|
-
end
|
63
234
|
end
|
64
235
|
end
|
65
236
|
end
|
@@ -1,357 +1,70 @@
|
|
1
1
|
module JsonapiCompliable
|
2
|
-
# Provides main interface to jsonapi_compliable
|
3
|
-
#
|
4
|
-
# This gets mixed in to a "context" class, such as a Rails controller.
|
5
2
|
module Base
|
6
3
|
extend ActiveSupport::Concern
|
7
4
|
|
8
|
-
included do
|
9
|
-
class << self
|
10
|
-
attr_accessor :_jsonapi_compliable, :_sideload_whitelist
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.inherited(klass)
|
14
|
-
super
|
15
|
-
klass._jsonapi_compliable = Class.new(_jsonapi_compliable)
|
16
|
-
klass._sideload_whitelist = _sideload_whitelist.dup if _sideload_whitelist
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
# @!classmethods
|
21
|
-
module ClassMethods
|
22
|
-
# Define your JSONAPI configuration
|
23
|
-
#
|
24
|
-
# @example Inline Resource
|
25
|
-
# # 'Quick and Dirty' solution that does not require a separate
|
26
|
-
# # Resource object
|
27
|
-
# class PostsController < ApplicationController
|
28
|
-
# jsonapi do
|
29
|
-
# type :posts
|
30
|
-
# use_adapter JsonapiCompliable::Adapters::ActiveRecord
|
31
|
-
#
|
32
|
-
# allow_filter :title
|
33
|
-
# end
|
34
|
-
# end
|
35
|
-
#
|
36
|
-
# @example Resource Class (preferred)
|
37
|
-
# # Make code reusable by encapsulating it in a Resource class
|
38
|
-
# class PostsController < ApplicationController
|
39
|
-
# jsonapi resource: PostResource
|
40
|
-
# end
|
41
|
-
#
|
42
|
-
# @see Resource
|
43
|
-
# @param resource [Resource] the Resource class associated to this endpoint
|
44
|
-
# @return [void]
|
45
|
-
def jsonapi(foo = 'bar', resource: nil, &blk)
|
46
|
-
if resource
|
47
|
-
self._jsonapi_compliable = resource
|
48
|
-
else
|
49
|
-
if !self._jsonapi_compliable
|
50
|
-
self._jsonapi_compliable = Class.new(JsonapiCompliable::Resource)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
self._jsonapi_compliable.class_eval(&blk) if blk
|
55
|
-
end
|
56
|
-
|
57
|
-
# Set the sideload whitelist. You may want to omit sideloads for
|
58
|
-
# security or performance reasons.
|
59
|
-
#
|
60
|
-
# Uses JSONAPI::IncludeDirective from {{http://jsonapi-rb.org jsonapi-rb}}
|
61
|
-
#
|
62
|
-
# @example Whitelisting Relationships
|
63
|
-
# # Given the following whitelist
|
64
|
-
# class PostsController < ApplicationResource
|
65
|
-
# jsonapi resource: MyResource
|
66
|
-
#
|
67
|
-
# sideload_whitelist({
|
68
|
-
# index: [:blog],
|
69
|
-
# show: [:blog, { comments: :author }]
|
70
|
-
# })
|
71
|
-
#
|
72
|
-
# # ... code ...
|
73
|
-
# end
|
74
|
-
#
|
75
|
-
# # A request to sideload 'tags'
|
76
|
-
# #
|
77
|
-
# # GET /posts/1?include=tags
|
78
|
-
# #
|
79
|
-
# # ...will silently fail.
|
80
|
-
# #
|
81
|
-
# # A request for comments and tags:
|
82
|
-
# #
|
83
|
-
# # GET /posts/1?include=tags,comments
|
84
|
-
# #
|
85
|
-
# # ...will only sideload comments
|
86
|
-
#
|
87
|
-
# @param [Hash, Array, Symbol] whitelist
|
88
|
-
# @see Query#include_hash
|
89
|
-
def sideload_whitelist(hash)
|
90
|
-
self._sideload_whitelist = JSONAPI::IncludeDirective.new(hash).to_hash
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
# @api private
|
95
|
-
def sideload_whitelist
|
96
|
-
self.class._sideload_whitelist || {}
|
97
|
-
end
|
98
|
-
|
99
|
-
# Returns an instance of the associated Resource
|
100
|
-
#
|
101
|
-
# In other words, if you configured your controller as:
|
102
|
-
#
|
103
|
-
# jsonapi resource: MyResource
|
104
|
-
#
|
105
|
-
# This returns MyResource.new
|
106
|
-
#
|
107
|
-
# @return [Resource] the configured Resource for this controller
|
108
5
|
def jsonapi_resource
|
109
|
-
@jsonapi_resource
|
110
|
-
resource = self.class._jsonapi_compliable
|
111
|
-
if resource.is_a?(Hash)
|
112
|
-
resource[action_name.to_sym].new
|
113
|
-
else
|
114
|
-
resource.new
|
115
|
-
end
|
116
|
-
end
|
6
|
+
@jsonapi_resource
|
117
7
|
end
|
118
8
|
|
119
|
-
# Instantiates the relevant Query object
|
120
|
-
#
|
121
|
-
# @see Query
|
122
|
-
# @return [Query] the Query object for this resource/params
|
123
9
|
def query
|
124
10
|
@query ||= Query.new(jsonapi_resource, params)
|
125
11
|
end
|
126
12
|
|
127
|
-
# @see Query#to_hash
|
128
|
-
# @return [Hash] the normalized query hash for only the *current* resource
|
129
13
|
def query_hash
|
130
|
-
@query_hash ||= query.to_hash
|
14
|
+
@query_hash ||= query.to_hash
|
131
15
|
end
|
132
16
|
|
133
|
-
# Tracks the current context so we can refer to it within any
|
134
|
-
# random object. Helpful for easy-access to things like the current
|
135
|
-
# user.
|
136
|
-
#
|
137
|
-
# @api private
|
138
|
-
# @yieldreturn Code to run within the current context
|
139
17
|
def wrap_context
|
140
|
-
|
18
|
+
JsonapiCompliable.with_context(jsonapi_context, action_name.to_sym) do
|
141
19
|
yield
|
142
20
|
end
|
143
21
|
end
|
144
22
|
|
145
|
-
# Override if you'd like the "context" to be something other than
|
146
|
-
# an instance of this class.
|
147
|
-
# In Rails, context is the controller instance.
|
148
|
-
#
|
149
|
-
# @example Overriding
|
150
|
-
# # within your controller
|
151
|
-
# def jsonapi_context
|
152
|
-
# current_user
|
153
|
-
# end
|
154
|
-
#
|
155
|
-
# # within a resource
|
156
|
-
# default_filter :by_user do |scope, context|
|
157
|
-
# scope.where(user_id: context.id)
|
158
|
-
# end
|
159
|
-
#
|
160
|
-
# @return the context object you'd like
|
161
23
|
def jsonapi_context
|
162
24
|
self
|
163
25
|
end
|
164
26
|
|
165
|
-
# Use when direct, low-level access to the scope is required.
|
166
|
-
#
|
167
|
-
# @example Show Action
|
168
|
-
# # Scope#resolve returns an array, but we only want to render
|
169
|
-
# # one object, not an array
|
170
|
-
# scope = jsonapi_scope(Employee.where(id: params[:id]))
|
171
|
-
# render_jsonapi(scope.resolve.first, scope: false)
|
172
|
-
#
|
173
|
-
# @example Scope Chaining
|
174
|
-
# # Chain onto scope after running through typical DSL
|
175
|
-
# # Here, we'll add active: true to our hash if the user
|
176
|
-
# # is filtering on something
|
177
|
-
# scope = jsonapi_scope({})
|
178
|
-
# scope.object.merge!(active: true) if scope.object[:filter]
|
179
|
-
#
|
180
|
-
# @see Resource#build_scope
|
181
|
-
# @return [Scope] the configured scope
|
182
27
|
def jsonapi_scope(scope, opts = {})
|
183
28
|
jsonapi_resource.build_scope(scope, query, opts)
|
184
29
|
end
|
185
30
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
end
|
191
|
-
|
192
|
-
# Create the resource model and process all nested relationships via the
|
193
|
-
# serialized parameters. Any error, including validation errors, will roll
|
194
|
-
# back the transaction.
|
195
|
-
#
|
196
|
-
# @example Basic Rails
|
197
|
-
# # Example Resource must have 'model'
|
198
|
-
# #
|
199
|
-
# # class PostResource < ApplicationResource
|
200
|
-
# # model Post
|
201
|
-
# # end
|
202
|
-
# def create
|
203
|
-
# post, success = jsonapi_create.to_a
|
204
|
-
#
|
205
|
-
# if success
|
206
|
-
# render_jsonapi(post, scope: false)
|
207
|
-
# else
|
208
|
-
# render_errors_for(post)
|
209
|
-
# end
|
210
|
-
# end
|
211
|
-
#
|
212
|
-
# @see Resource.model
|
213
|
-
# @see #resource
|
214
|
-
# @see #deserialized_params
|
215
|
-
# @return [Util::ValidationResponse]
|
216
|
-
def jsonapi_create
|
217
|
-
_persist do
|
218
|
-
jsonapi_resource.persist_with_relationships \
|
219
|
-
deserialized_params.meta,
|
220
|
-
deserialized_params.attributes,
|
221
|
-
deserialized_params.relationships
|
31
|
+
def normalized_params
|
32
|
+
normalized = params
|
33
|
+
if normalized.respond_to?(:to_unsafe_h)
|
34
|
+
normalized = normalized.to_unsafe_h.deep_symbolize_keys
|
222
35
|
end
|
36
|
+
normalized
|
223
37
|
end
|
224
38
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
# # Example Resource must have 'model'
|
231
|
-
# #
|
232
|
-
# # class PostResource < ApplicationResource
|
233
|
-
# # model Post
|
234
|
-
# # end
|
235
|
-
# def update
|
236
|
-
# post, success = jsonapi_update.to_a
|
237
|
-
#
|
238
|
-
# if success
|
239
|
-
# render_jsonapi(post, scope: false)
|
240
|
-
# else
|
241
|
-
# render_errors_for(post)
|
242
|
-
# end
|
243
|
-
# end
|
244
|
-
#
|
245
|
-
# @see #jsonapi_create
|
246
|
-
# @return [Util::ValidationResponse]
|
247
|
-
def jsonapi_update
|
248
|
-
_persist do
|
249
|
-
jsonapi_resource.persist_with_relationships \
|
250
|
-
deserialized_params.meta,
|
251
|
-
deserialized_params.attributes,
|
252
|
-
deserialized_params.relationships
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
# Delete the model
|
257
|
-
# Any error, including validation errors, will roll back the transaction.
|
258
|
-
#
|
259
|
-
# Note: +before_commit+ hooks still run unless excluded
|
260
|
-
#
|
261
|
-
# @return [Util::ValidationResponse]
|
262
|
-
def jsonapi_destroy
|
263
|
-
jsonapi_resource.transaction do
|
264
|
-
model = jsonapi_resource.destroy(params[:id])
|
265
|
-
validator = ::JsonapiCompliable::Util::ValidationResponse.new \
|
266
|
-
model, deserialized_params
|
267
|
-
validator.validate!
|
268
|
-
jsonapi_resource.before_commit(model, :destroy)
|
269
|
-
validator
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
# Similar to +render :json+ or +render :jsonapi+
|
274
|
-
#
|
275
|
-
# By default, this will "build" the scope via +#jsonapi_scope+. To avoid
|
276
|
-
# this, pass +scope: false+
|
277
|
-
#
|
278
|
-
# This builds relevant options and sends them to
|
279
|
-
# +JSONAPI::Serializable::SuccessRenderer#render+from
|
280
|
-
# {http://jsonapi-rb.org jsonapi-rb}
|
281
|
-
#
|
282
|
-
# @example Build Scope by Default
|
283
|
-
# # Employee.all returns an ActiveRecord::Relation. No SQL is fired at this point.
|
284
|
-
# # We further 'chain' onto this scope, applying pagination, sorting,
|
285
|
-
# # filters, etc that the user has requested.
|
286
|
-
# def index
|
287
|
-
# employees = Employee.all
|
288
|
-
# render_jsonapi(employees)
|
289
|
-
# end
|
290
|
-
#
|
291
|
-
# @example Avoid Building Scope by Default
|
292
|
-
# # Maybe we already manually scoped, and don't want to fire the logic twice
|
293
|
-
# # This code is equivalent to the above example
|
294
|
-
# def index
|
295
|
-
# scope = jsonapi_scope(Employee.all)
|
296
|
-
# # ... do other things with the scope ...
|
297
|
-
# render_jsonapi(scope.resolve, scope: false)
|
298
|
-
# end
|
299
|
-
#
|
300
|
-
# @param scope [Scope, Object] the scope to build or render.
|
301
|
-
# @param [Hash] opts the render options passed to {http://jsonapi-rb.org jsonapi-rb}
|
302
|
-
# @option opts [Boolean] :scope Default: true. Should we call #jsonapi_scope on this object?
|
303
|
-
# @see #jsonapi_scope
|
304
|
-
def render_jsonapi(scope, opts = {})
|
305
|
-
scope = jsonapi_scope(scope) unless opts[:scope] == false || scope.is_a?(JsonapiCompliable::Scope)
|
306
|
-
opts = default_jsonapi_render_options.merge(opts)
|
307
|
-
opts = Util::RenderOptions.generate(scope, query_hash, opts)
|
308
|
-
opts[:expose][:context] = self
|
309
|
-
|
310
|
-
if opts[:include].empty? && force_includes?
|
311
|
-
opts[:include] = deserialized_params.include_directive
|
312
|
-
end
|
313
|
-
|
314
|
-
perform_render_jsonapi(opts)
|
315
|
-
end
|
316
|
-
|
317
|
-
# Define a hash that will be automatically merged into your
|
318
|
-
# render_jsonapi call
|
319
|
-
#
|
320
|
-
# @example
|
321
|
-
# # this
|
322
|
-
# render_jsonapi(foo)
|
323
|
-
# # is equivalent to this
|
324
|
-
# render jsonapi: foo, default_jsonapi_render_options
|
325
|
-
#
|
326
|
-
# @see #render_jsonapi
|
327
|
-
# @return [Hash] the options hash you define
|
328
|
-
def default_jsonapi_render_options
|
329
|
-
{}.tap do |options|
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
|
-
private
|
334
|
-
|
335
|
-
def _persist
|
336
|
-
jsonapi_resource.transaction do
|
337
|
-
::JsonapiCompliable::Util::Hooks.record do
|
338
|
-
model = yield
|
339
|
-
validator = ::JsonapiCompliable::Util::ValidationResponse.new \
|
340
|
-
model, deserialized_params
|
341
|
-
validator.validate!
|
342
|
-
validator
|
39
|
+
def deserialized_params
|
40
|
+
@deserialized_params ||= begin
|
41
|
+
payload = normalized_params
|
42
|
+
if payload[:data] && payload[:data][:type]
|
43
|
+
JsonapiCompliable::Deserializer.new(payload)
|
343
44
|
end
|
344
45
|
end
|
345
46
|
end
|
346
47
|
|
347
|
-
def
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
48
|
+
def jsonapi_render_options
|
49
|
+
options = {}
|
50
|
+
options.merge!(default_jsonapi_render_options)
|
51
|
+
options[:meta] ||= {}
|
52
|
+
options[:expose] ||= {}
|
53
|
+
options[:expose][:context] = jsonapi_context
|
54
|
+
options
|
55
|
+
end
|
56
|
+
|
57
|
+
def proxy(base = nil, opts = {})
|
58
|
+
base ||= jsonapi_resource.base_scope
|
59
|
+
scope_opts = opts.slice :sideload_parent_length,
|
60
|
+
:default_paginate, :after_resolve
|
61
|
+
scope = jsonapi_scope(base, scope_opts)
|
62
|
+
ResourceProxy.new jsonapi_resource,
|
63
|
+
scope,
|
64
|
+
query,
|
65
|
+
payload: deserialized_params,
|
66
|
+
single: opts[:single],
|
67
|
+
raise_on_missing: opts[:raise_on_missing]
|
355
68
|
end
|
356
69
|
end
|
357
70
|
end
|