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: f0a9ae17435876f34d868d88ea187ae8844593a498f6d2d560c3ab2cfe1fa37a
4
- data.tar.gz: ea04580ad618ed1e15f28cb29ed079e64beead85d77479a52896c10aed226bc8
3
+ metadata.gz: ab8e500690ee54da42755e6243047dcc2cd78706c96dae29e18510aef2f9829a
4
+ data.tar.gz: 9e8c0990b2bf175effea734f306a806de6094984b6dca7cf2899c9c6e77bcc5a
5
5
  SHA512:
6
- metadata.gz: 3b596fb77e6bf656ce0fd7613ed2498019670b8576b022f6bda349d4f945d1502a2704bffb3d82a8cf2910ee0779f8fbcf2abae69bbd90e7734d59af1f2a8323
7
- data.tar.gz: 9c11d18a0805d17adb55b15d2e5b75e563c7e065bf0734e330c2584991ba0301a542466d9ee5d87387ecd97848451656c0740fa5488d77cd3f187b1f8988aacb
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.8
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[1..].map { |r| r.split.last(3) }.map { |r|
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`, and replace nil responses with blank ones. `payload`
68
- # must be already serialized to Ruby primitives.
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 payload.respond_to?(:to_json)
76
- format.json {
77
- kwargs = kwargs.merge(json_kwargs)
78
- render(json: payload || '', **kwargs)
79
- }
80
- end
81
- if payload.respond_to?(:to_xml)
82
- format.xml {
83
- kwargs = kwargs.merge(xml_kwargs)
84
- render(xml: payload || '', **kwargs)
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 = payload.to_json
90
- @xml_payload = payload.to_xml
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 default view
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 an action (or the current action if none given).
33
- def get_fields(action: nil)
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 list of parameters allowed for an action (or the current action if none given).
46
- def get_allowed_parameters(action: nil)
47
- allowed_action_parameters = self.class.allowed_action_parameters || {}
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 will, by default, be the current action name
50
- action = action_name.to_sym unless 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 @_get_field_values_from_request_body ||= (request.request_parameters.select { |p|
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 @_get_field_values_from_params ||= request.query_parameters.select { |p|
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
- if @record
182
- @record.destroy!
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
- def initialize(model: nil, **kwargs)
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
- @model = model || @controller.send(:get_model)
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 get_native_serializer_config
27
- fields = @controller.send(:get_fields)
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
- return @object.as_json(self.get_native_serializer_config)
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.8
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-06 00:00:00.000000000 Z
11
+ date: 2020-10-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails