rest_framework 0.5.6 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/rest_framework/controller_mixins/base.rb +47 -33
- data/lib/rest_framework/controller_mixins/models.rb +61 -42
- data/lib/rest_framework/filters.rb +12 -9
- data/lib/rest_framework/routers.rb +1 -1
- data/lib/rest_framework/serializers.rb +2 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 33c45fc367d9899fa2e47ea4c042a46ed381986e9210bf4574b61d1301c60fcc
|
4
|
+
data.tar.gz: 225adc8d9b5380e7e403765d7ec21331a61c9a8c562013781571dc84037560d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7178418a52918caf797f2a96bd1d39a5e8291d154ba335122b590e5534cc02124f5203feb24dade1f5dcb84ac45b281a7e4fb30274be943025e2f7850bd1cfca
|
7
|
+
data.tar.gz: e4195747856948df06aa0c396812d6ea3bbd3d374318b3c9f7a60c55747ae62db25ef76fc59e0705fd1531822304c62a416151772d29877aa4b723852015f2db
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.6.1
|
@@ -45,6 +45,7 @@ module RESTFramework::BaseControllerMixin
|
|
45
45
|
page_query_param: "page",
|
46
46
|
page_size_query_param: "page_size",
|
47
47
|
max_page_size: nil,
|
48
|
+
rescue_unknown_format_with: :json,
|
48
49
|
serializer_class: nil,
|
49
50
|
serialize_to_json: true,
|
50
51
|
serialize_to_xml: true,
|
@@ -145,42 +146,55 @@ module RESTFramework::BaseControllerMixin
|
|
145
146
|
raise RESTFramework::NilPassedToAPIResponseError
|
146
147
|
end
|
147
148
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
format.json {
|
154
|
-
jkwargs = kwargs.merge(json_kwargs)
|
155
|
-
render(json: payload, layout: false, **jkwargs)
|
156
|
-
} if self.class.serialize_to_json
|
157
|
-
format.xml {
|
158
|
-
xkwargs = kwargs.merge(xml_kwargs)
|
159
|
-
render(xml: payload, layout: false, **xkwargs)
|
160
|
-
} if self.class.serialize_to_xml
|
161
|
-
# TODO: possibly support more formats here if supported?
|
162
|
-
end
|
163
|
-
format.html {
|
164
|
-
@payload = payload
|
149
|
+
# Flag to track if we had to rescue unknown format.
|
150
|
+
already_rescued_unknown_format = false
|
151
|
+
|
152
|
+
begin
|
153
|
+
respond_to do |format|
|
165
154
|
if payload == ""
|
166
|
-
|
167
|
-
|
155
|
+
format.json { head(:no_content) } if self.class.serialize_to_json
|
156
|
+
format.xml { head(:no_content) } if self.class.serialize_to_xml
|
168
157
|
else
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
rescue ActionView::MissingTemplate # fallback to rest_framework layout
|
179
|
-
hkwargs[:layout] = "rest_framework"
|
180
|
-
hkwargs[:html] = ""
|
181
|
-
render(**hkwargs)
|
158
|
+
format.json {
|
159
|
+
jkwargs = kwargs.merge(json_kwargs)
|
160
|
+
render(json: payload, layout: false, **jkwargs)
|
161
|
+
} if self.class.serialize_to_json
|
162
|
+
format.xml {
|
163
|
+
xkwargs = kwargs.merge(xml_kwargs)
|
164
|
+
render(xml: payload, layout: false, **xkwargs)
|
165
|
+
} if self.class.serialize_to_xml
|
166
|
+
# TODO: possibly support more formats here if supported?
|
182
167
|
end
|
183
|
-
|
168
|
+
format.html {
|
169
|
+
@payload = payload
|
170
|
+
if payload == ""
|
171
|
+
@json_payload = "" if self.class.serialize_to_json
|
172
|
+
@xml_payload = "" if self.class.serialize_to_xml
|
173
|
+
else
|
174
|
+
@json_payload = payload.to_json if self.class.serialize_to_json
|
175
|
+
@xml_payload = payload.to_xml if self.class.serialize_to_xml
|
176
|
+
end
|
177
|
+
@template_logo_text ||= "Rails REST Framework"
|
178
|
+
@title ||= self.controller_name.camelize
|
179
|
+
@route_groups ||= RESTFramework::Utils.get_routes(Rails.application.routes, request)
|
180
|
+
hkwargs = kwargs.merge(html_kwargs)
|
181
|
+
begin
|
182
|
+
render(**hkwargs)
|
183
|
+
rescue ActionView::MissingTemplate # fallback to rest_framework layout
|
184
|
+
hkwargs[:layout] = "rest_framework"
|
185
|
+
hkwargs[:html] = ""
|
186
|
+
render(**hkwargs)
|
187
|
+
end
|
188
|
+
}
|
189
|
+
end
|
190
|
+
rescue ActionController::UnknownFormat
|
191
|
+
if !already_rescued_unknown_format && rescue_format = self.class.rescue_unknown_format_with
|
192
|
+
request.format = rescue_format
|
193
|
+
already_rescued_unknown_format = true
|
194
|
+
retry
|
195
|
+
else
|
196
|
+
raise
|
197
|
+
end
|
184
198
|
end
|
185
199
|
end
|
186
200
|
end
|
@@ -59,7 +59,7 @@ module RESTFramework::BaseModelControllerMixin
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def _get_specific_action_config(action_config_key, generic_config_key)
|
62
|
-
action_config = self.class.send(action_config_key) || {}
|
62
|
+
action_config = self.class.send(action_config_key)&.with_indifferent_access || {}
|
63
63
|
action = self.action_name&.to_sym
|
64
64
|
|
65
65
|
# Index action should use :list serializer if :index is not provided.
|
@@ -68,38 +68,45 @@ module RESTFramework::BaseModelControllerMixin
|
|
68
68
|
return (action_config[action] if action) || self.class.send(generic_config_key)
|
69
69
|
end
|
70
70
|
|
71
|
-
# Get a list of fields for the current action.
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
71
|
+
# Get a list of fields for the current action. Returning `nil` indicates that anything should be
|
72
|
+
# accepted unless `fallback` is true, in which case we should fallback to this controller's model
|
73
|
+
# columns, or en empty array.
|
74
|
+
def get_fields(fallback: false)
|
75
|
+
fields = _get_specific_action_config(:action_fields, :fields)
|
76
|
+
|
77
|
+
if fallback
|
78
|
+
fields ||= self.get_model&.column_names || []
|
79
|
+
end
|
80
|
+
|
81
|
+
return fields
|
78
82
|
end
|
79
83
|
|
80
84
|
# Get a list of find_by fields for the current action.
|
81
85
|
def get_find_by_fields
|
82
|
-
return self.class.find_by_fields
|
86
|
+
return self.class.find_by_fields || self.get_fields
|
83
87
|
end
|
84
88
|
|
85
|
-
# Get a list of find_by fields for the current action.
|
89
|
+
# Get a list of find_by fields for the current action. Default to the model column names.
|
86
90
|
def get_filterset_fields
|
87
|
-
return self.class.filterset_fields
|
91
|
+
return self.class.filterset_fields || self.get_fields(fallback: true)
|
88
92
|
end
|
89
93
|
|
90
94
|
# Get a list of ordering fields for the current action.
|
91
95
|
def get_ordering_fields
|
92
|
-
return self.class.ordering_fields
|
96
|
+
return self.class.ordering_fields || self.get_fields
|
93
97
|
end
|
94
98
|
|
95
|
-
# Get a list of search fields for the current action.
|
99
|
+
# Get a list of search fields for the current action. Default to the model column names.
|
96
100
|
def get_search_fields
|
97
|
-
return self.class.search_fields
|
101
|
+
return self.class.search_fields || self.get_fields(fallback: true)
|
98
102
|
end
|
99
103
|
|
100
104
|
# Get a list of parameters allowed for the current action.
|
101
105
|
def get_allowed_parameters
|
102
|
-
return _get_specific_action_config(
|
106
|
+
return _get_specific_action_config(
|
107
|
+
:allowed_action_parameters,
|
108
|
+
:allowed_parameters,
|
109
|
+
) || self.fields
|
103
110
|
end
|
104
111
|
|
105
112
|
# Helper to get the configured serializer class, or `NativeSerializer` as a default.
|
@@ -117,14 +124,18 @@ module RESTFramework::BaseModelControllerMixin
|
|
117
124
|
# Filter the request body for keys in current action's allowed_parameters/fields config.
|
118
125
|
def get_body_params
|
119
126
|
return @_get_body_params ||= begin
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
127
|
+
# Filter the request body and map to strings. Return all params if we cannot resolve a list of
|
128
|
+
# allowed parameters or fields.
|
129
|
+
body_params = if allowed_params = self.get_allowed_parameters&.map(&:to_s)
|
130
|
+
request.request_parameters.select { |p| allowed_params.include?(p) }
|
131
|
+
else
|
132
|
+
request.request_parameters
|
133
|
+
end
|
124
134
|
|
125
|
-
# Add query params in place of missing body params, if configured.
|
135
|
+
# Add query params in place of missing body params, if configured. If fields are not defined,
|
136
|
+
# fallback to using columns for this particular feature.
|
126
137
|
if self.class.accept_generic_params_as_body_params
|
127
|
-
(
|
138
|
+
(self.get_fields(fallback: true) - body_params.keys).each do |k|
|
128
139
|
if (value = params[k])
|
129
140
|
body_params[k] = value
|
130
141
|
end
|
@@ -137,7 +148,7 @@ module RESTFramework::BaseModelControllerMixin
|
|
137
148
|
end
|
138
149
|
|
139
150
|
# Filter fields in exclude_body_fields.
|
140
|
-
(self.class.exclude_body_fields || []).each { |f| body_params.delete(f
|
151
|
+
(self.class.exclude_body_fields || []).each { |f| body_params.delete(f) }
|
141
152
|
|
142
153
|
body_params
|
143
154
|
end
|
@@ -181,13 +192,21 @@ module RESTFramework::BaseModelControllerMixin
|
|
181
192
|
|
182
193
|
# Get a single record by primary key or another column, if allowed.
|
183
194
|
def get_record
|
195
|
+
# Cache the result.
|
196
|
+
return @_get_record if @_get_record
|
197
|
+
|
184
198
|
recordset = self.get_recordset
|
185
|
-
find_by_fields = self.get_find_by_fields
|
186
199
|
find_by_key = self.get_model.primary_key
|
187
200
|
|
188
201
|
# Find by another column if it's permitted.
|
189
|
-
if
|
190
|
-
|
202
|
+
if find_by_param = self.class.find_by_query_param.presence
|
203
|
+
if find_by = params[find_by_param].presence
|
204
|
+
find_by_fields = self.get_find_by_fields&.map(&:to_s)
|
205
|
+
|
206
|
+
if !find_by_fields || find_by.in?(find_by_fields)
|
207
|
+
find_by_key = find_by
|
208
|
+
end
|
209
|
+
end
|
191
210
|
end
|
192
211
|
|
193
212
|
# Filter recordset, if configured.
|
@@ -196,18 +215,18 @@ module RESTFramework::BaseModelControllerMixin
|
|
196
215
|
end
|
197
216
|
|
198
217
|
# Return the record. Route key is always :id by Rails convention.
|
199
|
-
return recordset.find_by!(find_by_key => params[:id])
|
218
|
+
return @_get_record = recordset.find_by!(find_by_key => params[:id])
|
200
219
|
end
|
201
220
|
end
|
202
221
|
|
203
222
|
# Mixin for listing records.
|
204
223
|
module RESTFramework::ListModelMixin
|
205
224
|
def index
|
206
|
-
api_response(self.
|
225
|
+
api_response(self.index!)
|
207
226
|
end
|
208
227
|
|
209
|
-
def
|
210
|
-
@records
|
228
|
+
def index!
|
229
|
+
@records ||= self.get_filtered_data(self.get_recordset)
|
211
230
|
|
212
231
|
# Handle pagination, if enabled.
|
213
232
|
if self.class.paginator_class
|
@@ -224,11 +243,11 @@ end
|
|
224
243
|
# Mixin for showing records.
|
225
244
|
module RESTFramework::ShowModelMixin
|
226
245
|
def show
|
227
|
-
api_response(self.
|
246
|
+
api_response(self.show!)
|
228
247
|
end
|
229
248
|
|
230
|
-
def
|
231
|
-
@record
|
249
|
+
def show!
|
250
|
+
@record ||= self.get_record
|
232
251
|
return self.get_serializer_class.new(@record, controller: self).serialize
|
233
252
|
end
|
234
253
|
end
|
@@ -236,16 +255,16 @@ end
|
|
236
255
|
# Mixin for creating records.
|
237
256
|
module RESTFramework::CreateModelMixin
|
238
257
|
def create
|
239
|
-
api_response(self.
|
258
|
+
api_response(self.create!)
|
240
259
|
end
|
241
260
|
|
242
|
-
def
|
261
|
+
def create!
|
243
262
|
if self.get_recordset.respond_to?(:create!) && self.create_from_recordset
|
244
263
|
# Create with any properties inherited from the recordset.
|
245
|
-
@record
|
264
|
+
@record ||= self.get_recordset.create!(self.get_create_params)
|
246
265
|
else
|
247
266
|
# Otherwise, perform a "bare" create.
|
248
|
-
@record
|
267
|
+
@record ||= self.get_model.create!(self.get_create_params)
|
249
268
|
end
|
250
269
|
|
251
270
|
return self.get_serializer_class.new(@record, controller: self).serialize
|
@@ -255,11 +274,11 @@ end
|
|
255
274
|
# Mixin for updating records.
|
256
275
|
module RESTFramework::UpdateModelMixin
|
257
276
|
def update
|
258
|
-
api_response(self.
|
277
|
+
api_response(self.update!)
|
259
278
|
end
|
260
279
|
|
261
|
-
def
|
262
|
-
@record
|
280
|
+
def update!
|
281
|
+
@record ||= self.get_record
|
263
282
|
@record.update!(self.get_update_params)
|
264
283
|
return self.get_serializer_class.new(@record, controller: self).serialize
|
265
284
|
end
|
@@ -268,12 +287,12 @@ end
|
|
268
287
|
# Mixin for destroying records.
|
269
288
|
module RESTFramework::DestroyModelMixin
|
270
289
|
def destroy
|
271
|
-
self.
|
290
|
+
self.destroy!
|
272
291
|
api_response("")
|
273
292
|
end
|
274
293
|
|
275
|
-
def
|
276
|
-
@record
|
294
|
+
def destroy!
|
295
|
+
@record ||= self.get_record
|
277
296
|
@record.destroy!
|
278
297
|
end
|
279
298
|
end
|
@@ -13,15 +13,17 @@ end
|
|
13
13
|
class RESTFramework::ModelFilter < RESTFramework::BaseFilter
|
14
14
|
# Filter params for keys allowed by the current action's filterset_fields/fields config.
|
15
15
|
def _get_filter_params
|
16
|
-
fields
|
17
|
-
|
18
|
-
fields.include?(p)
|
19
|
-
|
16
|
+
# Map filterset fields to strings because query parameter keys are strings.
|
17
|
+
if fields = @controller.get_filterset_fields&.map(&:to_s)
|
18
|
+
return @controller.request.query_parameters.select { |p, _| fields.include?(p) }
|
19
|
+
end
|
20
|
+
|
21
|
+
return @controller.request.query_parameters.to_h
|
20
22
|
end
|
21
23
|
|
22
24
|
# Filter data according to the request query parameters.
|
23
25
|
def get_filtered_data(data)
|
24
|
-
filter_params = self._get_filter_params
|
26
|
+
filter_params = self._get_filter_params.symbolize_keys
|
25
27
|
unless filter_params.blank?
|
26
28
|
return data.where(**filter_params)
|
27
29
|
end
|
@@ -36,11 +38,12 @@ class RESTFramework::ModelOrderingFilter < RESTFramework::BaseFilter
|
|
36
38
|
def _get_ordering
|
37
39
|
return nil if @controller.class.ordering_query_param.blank?
|
38
40
|
|
39
|
-
ordering_fields
|
41
|
+
# Ensure ordering_fields are strings since the split param will be strings.
|
42
|
+
ordering_fields = @controller.get_ordering_fields&.map(&:to_s)
|
40
43
|
order_string = @controller.params[@controller.class.ordering_query_param]
|
41
44
|
|
42
45
|
unless order_string.blank?
|
43
|
-
ordering = {}
|
46
|
+
ordering = {}.with_indifferent_access
|
44
47
|
order_string.split(",").each do |field|
|
45
48
|
if field[0] == "-"
|
46
49
|
column = field[1..-1]
|
@@ -49,8 +52,8 @@ class RESTFramework::ModelOrderingFilter < RESTFramework::BaseFilter
|
|
49
52
|
column = field
|
50
53
|
direction = :asc
|
51
54
|
end
|
52
|
-
if column.in?(ordering_fields)
|
53
|
-
ordering[column
|
55
|
+
if !ordering_fields || column.in?(ordering_fields)
|
56
|
+
ordering[column] = direction
|
54
57
|
end
|
55
58
|
end
|
56
59
|
return ordering
|
@@ -6,7 +6,7 @@ module ActionDispatch::Routing
|
|
6
6
|
# Internal interface to get the controller class from the name and current scope.
|
7
7
|
def _get_controller_class(name, pluralize: true, fallback_reverse_pluralization: true)
|
8
8
|
# Get class name.
|
9
|
-
name = name.to_s.camelize #
|
9
|
+
name = name.to_s.camelize # Camelize to leave plural names plural.
|
10
10
|
name = name.pluralize if pluralize
|
11
11
|
if name == name.pluralize
|
12
12
|
name_reverse = name.singularize
|
@@ -212,9 +212,8 @@ class RESTFramework::NativeSerializer < RESTFramework::BaseSerializer
|
|
212
212
|
return serializer_config.deep_dup
|
213
213
|
end
|
214
214
|
|
215
|
-
# If the config wasn't determined, build a serializer config from
|
216
|
-
fields = @controller
|
217
|
-
if fields
|
215
|
+
# If the config wasn't determined, build a serializer config from controller fields.
|
216
|
+
if fields = @controller&.get_fields
|
218
217
|
fields = fields.deep_dup
|
219
218
|
|
220
219
|
if @model
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rest_framework
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gregory N. Schmit
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-08-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|