rest_framework 0.0.8 → 0.0.14
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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab8e500690ee54da42755e6243047dcc2cd78706c96dae29e18510aef2f9829a
|
4
|
+
data.tar.gz: 9e8c0990b2bf175effea734f306a806de6094984b6dca7cf2899c9c6e77bcc5a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 730b8dcf9e9febb6d6adee7672a3bb1d8458498b6c17b1ec483878a5b8d28638a11f15c71745d9ba06d2eb41e64834a7e591390da3d5d64e1daa30b5244046b3
|
7
|
+
data.tar.gz: 544814fbe3bc83bdd6661346bae020ce8f74a0ea8edab9180d88654e09d51b458f5eed5732916c58aff9961da6b6224776d9bc6aff9d01b6519ab0cfe5e2641c
|
@@ -19,7 +19,7 @@
|
|
19
19
|
<div class="container py-3">
|
20
20
|
<div class="container">
|
21
21
|
<div class="row">
|
22
|
-
<h1><%= @title %></h1>
|
22
|
+
<h1><%= (@header_text if defined? @header_text) || @title %></h1>
|
23
23
|
</div>
|
24
24
|
<hr/>
|
25
25
|
<% if @json_payload || @xml_payload %>
|
@@ -46,7 +46,7 @@
|
|
46
46
|
<div class="tab-content w-100 pt-3">
|
47
47
|
<div class="tab-pane fade show active" id="tab-json" role="tab">
|
48
48
|
<% if @json_payload %>
|
49
|
-
<div><pre><code class="language-json"><%= JSON.pretty_generate(JSON.parse(@json_payload)) %></code></pre></div>
|
49
|
+
<div><pre><code class="language-json"><%= JSON.pretty_generate(JSON.parse(@json_payload)) unless @json_payload == '' %></code></pre></div>
|
50
50
|
<% end %>
|
51
51
|
</div>
|
52
52
|
<div class="tab-pane fade" id="tab-xml" role="tab">
|
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.14
|
@@ -34,8 +34,15 @@ module RESTFramework
|
|
34
34
|
:skip_actions,
|
35
35
|
:paginator_class,
|
36
36
|
])
|
37
|
+
|
38
|
+
# skip csrf since this is an API
|
39
|
+
base.skip_before_action(:verify_authenticity_token) rescue nil
|
40
|
+
|
41
|
+
# handle some common exceptions
|
37
42
|
base.rescue_from(ActiveRecord::RecordNotFound, with: :record_not_found)
|
38
43
|
base.rescue_from(ActiveRecord::RecordInvalid, with: :record_invalid)
|
44
|
+
base.rescue_from(ActiveRecord::RecordNotSaved, with: :record_not_saved)
|
45
|
+
base.rescue_from(ActiveRecord::RecordNotDestroyed, with: :record_not_destroyed)
|
39
46
|
end
|
40
47
|
end
|
41
48
|
|
@@ -51,6 +58,14 @@ module RESTFramework
|
|
51
58
|
return api_response({message: "Record not found.", exception: e}, status: 404)
|
52
59
|
end
|
53
60
|
|
61
|
+
def record_not_saved(e)
|
62
|
+
return api_response({message: "Record not saved.", exception: e}, status: 406)
|
63
|
+
end
|
64
|
+
|
65
|
+
def record_not_destroyed(e)
|
66
|
+
return api_response({message: "Record not destroyed.", exception: e}, status: 406)
|
67
|
+
end
|
68
|
+
|
54
69
|
def _get_routes
|
55
70
|
begin
|
56
71
|
formatter = ActionDispatch::Routing::ConsoleFormatter::Sheet
|
@@ -59,42 +74,55 @@ module RESTFramework
|
|
59
74
|
end
|
60
75
|
return ActionDispatch::Routing::RoutesInspector.new(Rails.application.routes.routes).format(
|
61
76
|
formatter.new
|
62
|
-
).lines
|
77
|
+
).lines.drop(1).map { |r| r.split.last(3) }.map { |r|
|
63
78
|
{verb: r[0], path: r[1], action: r[2]}
|
64
79
|
}.select { |r| r[:path].start_with?(request.path) }
|
65
80
|
end
|
66
81
|
|
67
|
-
# Helper alias for `respond_to`/`render
|
68
|
-
#
|
82
|
+
# Helper alias for `respond_to`/`render`. `payload` should be already serialized to Ruby
|
83
|
+
# primitives.
|
69
84
|
def api_response(payload, html_kwargs: nil, json_kwargs: nil, xml_kwargs: nil, **kwargs)
|
70
85
|
html_kwargs ||= {}
|
71
86
|
json_kwargs ||= {}
|
72
87
|
xml_kwargs ||= {}
|
73
88
|
|
89
|
+
# allow blank (no-content) responses
|
90
|
+
@blank = kwargs[:blank]
|
91
|
+
|
74
92
|
respond_to do |format|
|
75
|
-
if
|
76
|
-
format.json {
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
93
|
+
if @blank
|
94
|
+
format.json {head :no_content}
|
95
|
+
format.xml {head :no_content}
|
96
|
+
else
|
97
|
+
if payload.respond_to?(:to_json)
|
98
|
+
format.json {
|
99
|
+
kwargs = kwargs.merge(json_kwargs)
|
100
|
+
render(json: payload, layout: false, **kwargs)
|
101
|
+
}
|
102
|
+
end
|
103
|
+
if payload.respond_to?(:to_xml)
|
104
|
+
format.xml {
|
105
|
+
kwargs = kwargs.merge(xml_kwargs)
|
106
|
+
render(xml: payload, layout: false, **kwargs)
|
107
|
+
}
|
108
|
+
end
|
86
109
|
end
|
87
110
|
format.html {
|
88
111
|
@payload = payload
|
89
|
-
@json_payload =
|
90
|
-
@xml_payload =
|
112
|
+
@json_payload = ''
|
113
|
+
@xml_payload = ''
|
114
|
+
unless @blank
|
115
|
+
@json_payload = payload.to_json if payload.respond_to?(:to_json)
|
116
|
+
@xml_payload = payload.to_xml if payload.respond_to?(:to_xml)
|
117
|
+
end
|
91
118
|
@template_logo_text ||= "Rails REST Framework"
|
92
119
|
@title ||= self.controller_name.camelize
|
93
120
|
@routes ||= self._get_routes
|
94
121
|
kwargs = kwargs.merge(html_kwargs)
|
95
122
|
begin
|
96
123
|
render(**kwargs)
|
97
|
-
rescue ActionView::MissingTemplate # fallback to rest_framework
|
124
|
+
rescue ActionView::MissingTemplate # fallback to rest_framework layout/view
|
125
|
+
kwargs[:layout] = "rest_framework"
|
98
126
|
kwargs[:template] = "rest_framework/default"
|
99
127
|
end
|
100
128
|
render(**kwargs)
|
@@ -13,6 +13,8 @@ module RESTFramework
|
|
13
13
|
:recordset,
|
14
14
|
:fields,
|
15
15
|
:action_fields,
|
16
|
+
:native_serializer_config,
|
17
|
+
:native_serializer_action_config,
|
16
18
|
:filterset_fields,
|
17
19
|
:allowed_parameters,
|
18
20
|
:allowed_action_parameters,
|
@@ -29,36 +31,43 @@ module RESTFramework
|
|
29
31
|
return self.class.serializer_class || NativeModelSerializer
|
30
32
|
end
|
31
33
|
|
32
|
-
# Get a list of fields for
|
33
|
-
def get_fields
|
34
|
+
# Get a list of fields for the current action.
|
35
|
+
def get_fields
|
34
36
|
action_fields = self.class.action_fields || {}
|
35
|
-
|
36
|
-
# action will, by default, be the current action name
|
37
|
-
action = action_name.to_sym unless action
|
37
|
+
action = self.action_name.to_sym
|
38
38
|
|
39
39
|
# index action should use :list fields if :index is not provided
|
40
40
|
action = :list if action == :index && !action_fields.key?(:index)
|
41
41
|
|
42
|
-
return action_fields[action] || self.class.fields || []
|
42
|
+
return (action_fields[action] if action) || self.class.fields || []
|
43
43
|
end
|
44
44
|
|
45
|
-
# Get a
|
46
|
-
def
|
47
|
-
|
45
|
+
# Get a native serializer config for the current action.
|
46
|
+
def get_native_serializer_config
|
47
|
+
action_serializer_config = self.class.native_serializer_action_config || {}
|
48
|
+
action = self.action_name.to_sym
|
48
49
|
|
49
|
-
# action
|
50
|
-
action =
|
50
|
+
# index action should use :list serializer config if :index is not provided
|
51
|
+
action = :list if action == :index && !action_serializer_config.key?(:index)
|
52
|
+
|
53
|
+
return (action_serializer_config[action] if action) || self.class.native_serializer_config
|
54
|
+
end
|
55
|
+
|
56
|
+
# Get a list of parameters allowed for the current action.
|
57
|
+
def get_allowed_parameters
|
58
|
+
allowed_action_parameters = self.class.allowed_action_parameters || {}
|
59
|
+
action = self.action_name.to_sym
|
51
60
|
|
52
61
|
# index action should use :list allowed parameters if :index is not provided
|
53
62
|
action = :list if action == :index && !allowed_action_parameters.key?(:index)
|
54
63
|
|
55
|
-
return allowed_action_parameters[action] || self.class.allowed_parameters
|
64
|
+
return (allowed_action_parameters[action] if action) || self.class.allowed_parameters
|
56
65
|
end
|
57
66
|
|
58
67
|
# Filter the request body for keys in current action's allowed_parameters/fields config.
|
59
68
|
def _get_parameter_values_from_request_body
|
60
69
|
fields = self.get_allowed_parameters || self.get_fields
|
61
|
-
return @
|
70
|
+
return @_get_parameter_values_from_request_body ||= (request.request_parameters.select { |p|
|
62
71
|
fields.include?(p.to_sym) || fields.include?(p.to_s)
|
63
72
|
})
|
64
73
|
end
|
@@ -68,7 +77,7 @@ module RESTFramework
|
|
68
77
|
# Filter params for keys allowed by the current action's filterset_fields/fields config.
|
69
78
|
def _get_filterset_values_from_params
|
70
79
|
fields = self.filterset_fields || self.get_fields
|
71
|
-
return @
|
80
|
+
return @_get_filterset_values_from_params ||= request.query_parameters.select { |p|
|
72
81
|
fields.include?(p.to_sym) || fields.include?(p.to_s)
|
73
82
|
}
|
74
83
|
end
|
@@ -178,12 +187,8 @@ module RESTFramework
|
|
178
187
|
module DestroyModelMixin
|
179
188
|
def destroy
|
180
189
|
@record = self.get_record
|
181
|
-
|
182
|
-
|
183
|
-
api_response('')
|
184
|
-
else
|
185
|
-
api_response({detail: "Method 'DELETE' not allowed."}, status: 405)
|
186
|
-
end
|
190
|
+
@record.destroy!
|
191
|
+
api_response(nil)
|
187
192
|
end
|
188
193
|
end
|
189
194
|
|
@@ -7,34 +7,102 @@ module RESTFramework
|
|
7
7
|
@data = data
|
8
8
|
@controller = controller
|
9
9
|
end
|
10
|
-
|
11
|
-
def is_valid
|
12
|
-
return true
|
13
|
-
end
|
14
10
|
end
|
15
11
|
|
16
12
|
# This serializer uses `.as_json` to serialize objects. Despite the name, `.as_json` is a Rails
|
17
13
|
# method which converts objects to Ruby primitives (with the top-level being either an array or a
|
18
14
|
# hash).
|
19
15
|
class NativeModelSerializer < BaseSerializer
|
20
|
-
|
16
|
+
class_attribute :config
|
17
|
+
class_attribute :singular_config
|
18
|
+
class_attribute :plural_config
|
19
|
+
class_attribute :action_config
|
20
|
+
|
21
|
+
def initialize(model: nil, many: nil, **kwargs)
|
21
22
|
super(**kwargs)
|
22
|
-
@
|
23
|
+
@many = many
|
24
|
+
@model = model || (@controller ? @controller.send(:get_model) : nil)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Get controller action, if possible.
|
28
|
+
def get_action
|
29
|
+
return @controller&.action_name&.to_sym
|
30
|
+
end
|
31
|
+
|
32
|
+
# Get a locally defined configuration, if one is defined.
|
33
|
+
def get_local_serializer_config
|
34
|
+
action = self.get_action
|
35
|
+
|
36
|
+
if action && self.action_config
|
37
|
+
# index action should use :list serializer config if :index is not provided
|
38
|
+
action = :list if action == :index && !self.action_config.key?(:index)
|
39
|
+
|
40
|
+
return self.action_config[action] if self.action_config[action]
|
41
|
+
end
|
42
|
+
|
43
|
+
# no action_config, so try singular/plural config
|
44
|
+
return self.plural_config if @many && self.plural_config
|
45
|
+
return self.singular_config if !@many && self.singular_config
|
46
|
+
|
47
|
+
# lastly, try the default config
|
48
|
+
return self.config
|
23
49
|
end
|
24
50
|
|
25
51
|
# Get a configuration passable to `as_json` for the model.
|
26
|
-
def
|
27
|
-
|
52
|
+
def get_serializer_config
|
53
|
+
# return a locally defined serializer config if one is defined
|
54
|
+
local_config = self.get_local_serializer_config
|
55
|
+
return local_config if local_config
|
56
|
+
|
57
|
+
# return a serializer config if one is defined
|
58
|
+
serializer_config = @controller.send(:get_native_serializer_config)
|
59
|
+
return serializer_config if serializer_config
|
60
|
+
|
61
|
+
# otherwise, build a serializer config from fields
|
62
|
+
fields = @controller.send(:get_fields) if @controller
|
28
63
|
unless fields.blank?
|
29
64
|
columns, methods = fields.partition { |f| f.to_s.in?(@model.column_names) }
|
30
65
|
return {only: columns, methods: methods}
|
31
66
|
end
|
67
|
+
|
32
68
|
return {}
|
33
69
|
end
|
34
70
|
|
35
71
|
# Convert the object(s) to Ruby primitives.
|
36
72
|
def serialize
|
37
|
-
|
73
|
+
if @object
|
74
|
+
@many = @object.respond_to?(:each) if @many.nil?
|
75
|
+
return @object.as_json(self.get_serializer_config)
|
76
|
+
end
|
77
|
+
return nil
|
78
|
+
end
|
79
|
+
|
80
|
+
# Allow a serializer instance to be used as a hash directly in a nested serializer config.
|
81
|
+
def [](key)
|
82
|
+
unless instance_variable_defined?(:@_nested_config)
|
83
|
+
@_nested_config = self.get_serializer_config
|
84
|
+
end
|
85
|
+
return @_nested_config[key]
|
86
|
+
end
|
87
|
+
def []=(key, value)
|
88
|
+
unless instance_variable_defined?(:@_nested_config)
|
89
|
+
@_nested_config = self.get_serializer_config
|
90
|
+
end
|
91
|
+
return @_nested_config[key] = value
|
92
|
+
end
|
93
|
+
|
94
|
+
# Allow a serializer class to be used as a hash directly in a nested serializer config.
|
95
|
+
def self.[](key)
|
96
|
+
unless instance_variable_defined?(:@_nested_config)
|
97
|
+
@_nested_config = self.new.get_serializer_config
|
98
|
+
end
|
99
|
+
return @_nested_config[key]
|
100
|
+
end
|
101
|
+
def self.[]=(key, value)
|
102
|
+
unless instance_variable_defined?(:@_nested_config)
|
103
|
+
@_nested_config = self.new.get_serializer_config
|
104
|
+
end
|
105
|
+
return @_nested_config[key] = value
|
38
106
|
end
|
39
107
|
end
|
40
108
|
end
|
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.0.
|
4
|
+
version: 0.0.14
|
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: 2020-10-
|
11
|
+
date: 2020-10-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|