rest_framework 0.2.0 → 0.3.0
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 +4 -4
- data/README.md +1 -0
- data/VERSION +1 -0
- data/lib/rest_framework/controller_mixins/base.rb +17 -13
- data/lib/rest_framework/controller_mixins/models.rb +54 -25
- data/lib/rest_framework/errors.rb +2 -0
- data/lib/rest_framework/filters.rb +14 -6
- data/lib/rest_framework/generators/controller_generator.rb +58 -17
- data/lib/rest_framework/routers.rb +29 -39
- data/lib/rest_framework/serializers.rb +11 -13
- data/lib/rest_framework/version.rb +18 -21
- metadata +3 -3
- data/lib/rest_framework/VERSION_STAMP +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a4c53fa557df9090c749745efce556214252b76e2115df09917970e9a9c8b5e
|
4
|
+
data.tar.gz: 5c33946ae697618f726532e9b45056f2e112d3f81f6efb5c9a37ab8d9b3b002e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ddfd6544b96284e871684d2f448e622631bd88631ea78ebe4170d2ff2fe4f1654901ef86a96584e3c5d0a2538bcef5d29f85152795aa689df58fc98cb05f7b3b
|
7
|
+
data.tar.gz: 1ab60515fcf543c0df574a6cf3913648736d19d559b1d9fbe55f891ce3e6926026357369580430ada33b6e294a081d8058b297bb3f146b3d17f4671b10683d55
|
data/README.md
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
[](https://badge.fury.io/rb/rest_framework)
|
4
4
|
[](https://travis-ci.org/gregschmit/rails-rest-framework)
|
5
5
|
[](https://coveralls.io/github/gregschmit/rails-rest-framework?branch=master)
|
6
|
+
[](https://codeclimate.com/github/gregschmit/rails-rest-framework/maintainability)
|
6
7
|
|
7
8
|
A framework for DRY RESTful APIs in Ruby on Rails.
|
8
9
|
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.3.0
|
@@ -79,8 +79,12 @@ module RESTFramework::BaseControllerMixin
|
|
79
79
|
|
80
80
|
protected
|
81
81
|
|
82
|
-
# Helper to get
|
83
|
-
|
82
|
+
# Helper to get the configured serializer class.
|
83
|
+
def get_serializer_class
|
84
|
+
return self.class.serializer_class
|
85
|
+
end
|
86
|
+
|
87
|
+
# Helper to get filtering backends, defaulting to no backends.
|
84
88
|
def get_filter_backends
|
85
89
|
return self.class.filter_backends || []
|
86
90
|
end
|
@@ -95,16 +99,10 @@ module RESTFramework::BaseControllerMixin
|
|
95
99
|
return data
|
96
100
|
end
|
97
101
|
|
98
|
-
# Helper to get the configured serializer class.
|
99
|
-
# @return [RESTFramework::BaseSerializer]
|
100
|
-
def get_serializer_class
|
101
|
-
return self.class.serializer_class
|
102
|
-
end
|
103
|
-
|
104
102
|
def record_invalid(e)
|
105
|
-
return api_response(
|
106
|
-
|
107
|
-
)
|
103
|
+
return api_response({
|
104
|
+
message: "Record invalid.", exception: e, errors: e.record&.errors
|
105
|
+
}, status: 400)
|
108
106
|
end
|
109
107
|
|
110
108
|
def record_not_found(e)
|
@@ -112,11 +110,15 @@ module RESTFramework::BaseControllerMixin
|
|
112
110
|
end
|
113
111
|
|
114
112
|
def record_not_saved(e)
|
115
|
-
return api_response({
|
113
|
+
return api_response({
|
114
|
+
message: "Record not saved.", exception: e, errors: e.record&.errors
|
115
|
+
}, status: 406)
|
116
116
|
end
|
117
117
|
|
118
118
|
def record_not_destroyed(e)
|
119
|
-
return api_response({
|
119
|
+
return api_response({
|
120
|
+
message: "Record not destroyed.", exception: e, errors: e.record&.errors
|
121
|
+
}, status: 406)
|
120
122
|
end
|
121
123
|
|
122
124
|
# Helper for showing routes under a controller action, used for the browsable API.
|
@@ -124,7 +126,9 @@ module RESTFramework::BaseControllerMixin
|
|
124
126
|
begin
|
125
127
|
formatter = ActionDispatch::Routing::ConsoleFormatter::Sheet
|
126
128
|
rescue NameError
|
129
|
+
# :nocov:
|
127
130
|
formatter = ActionDispatch::Routing::ConsoleFormatter
|
131
|
+
# :nocov:
|
128
132
|
end
|
129
133
|
return ActionDispatch::Routing::RoutesInspector.new(Rails.application.routes.routes).format(
|
130
134
|
formatter.new
|
@@ -20,6 +20,10 @@ module RESTFramework::BaseModelControllerMixin
|
|
20
20
|
fields: nil,
|
21
21
|
action_fields: nil,
|
22
22
|
|
23
|
+
# Attributes for finding records.
|
24
|
+
find_by_fields: nil,
|
25
|
+
find_by_query_param: 'find_by',
|
26
|
+
|
23
27
|
# Attributes for create/update parameters.
|
24
28
|
allowed_parameters: nil,
|
25
29
|
allowed_action_parameters: nil,
|
@@ -35,7 +39,8 @@ module RESTFramework::BaseModelControllerMixin
|
|
35
39
|
ordering_query_param: 'ordering',
|
36
40
|
|
37
41
|
# Other misc attributes.
|
38
|
-
|
42
|
+
create_from_recordset: true, # Option for `recordset.create` vs `Model.create` behavior.
|
43
|
+
filter_recordset_before_find: true, # Option to control if filtering is done before find.
|
39
44
|
}.each do |a, default|
|
40
45
|
unless base.respond_to?(a)
|
41
46
|
base.class_attribute(a)
|
@@ -60,11 +65,6 @@ module RESTFramework::BaseModelControllerMixin
|
|
60
65
|
return (action_config[action] if action) || self.class.send(generic_config_key)
|
61
66
|
end
|
62
67
|
|
63
|
-
# Get a list of parameters allowed for the current action.
|
64
|
-
def get_allowed_parameters
|
65
|
-
return _get_specific_action_config(:allowed_action_parameters, :allowed_parameters)&.map(&:to_s)
|
66
|
-
end
|
67
|
-
|
68
68
|
# Get a list of fields for the current action.
|
69
69
|
def get_fields
|
70
70
|
return (
|
@@ -74,14 +74,32 @@ module RESTFramework::BaseModelControllerMixin
|
|
74
74
|
)
|
75
75
|
end
|
76
76
|
|
77
|
+
# Get a list of find_by fields for the current action.
|
78
|
+
def get_find_by_fields
|
79
|
+
return self.class.find_by_fields&.map(&:to_s) || self.get_fields
|
80
|
+
end
|
81
|
+
|
82
|
+
# Get a list of find_by fields for the current action.
|
83
|
+
def get_filterset_fields
|
84
|
+
return self.class.filterset_fields&.map(&:to_s) || self.get_fields
|
85
|
+
end
|
86
|
+
|
87
|
+
# Get a list of ordering fields for the current action.
|
88
|
+
def get_ordering_fields
|
89
|
+
return self.class.ordering_fields&.map(&:to_s) || self.get_fields
|
90
|
+
end
|
91
|
+
|
92
|
+
# Get a list of parameters allowed for the current action.
|
93
|
+
def get_allowed_parameters
|
94
|
+
return _get_specific_action_config(:allowed_action_parameters, :allowed_parameters)&.map(&:to_s)
|
95
|
+
end
|
96
|
+
|
77
97
|
# Helper to get the configured serializer class, or `NativeSerializer` as a default.
|
78
|
-
# @return [RESTFramework::BaseSerializer]
|
79
98
|
def get_serializer_class
|
80
99
|
return self.class.serializer_class || RESTFramework::NativeSerializer
|
81
100
|
end
|
82
101
|
|
83
|
-
#
|
84
|
-
# @return [RESTFramework::BaseFilter]
|
102
|
+
# Helper to get filtering backends, defaulting to using `ModelFilter` and `ModelOrderingFilter`.
|
85
103
|
def get_filter_backends
|
86
104
|
return self.class.filter_backends || [
|
87
105
|
RESTFramework::ModelFilter, RESTFramework::ModelOrderingFilter
|
@@ -94,9 +112,7 @@ module RESTFramework::BaseModelControllerMixin
|
|
94
112
|
fields = self.get_allowed_parameters || self.get_fields
|
95
113
|
|
96
114
|
# Filter the request body.
|
97
|
-
body_params = request.request_parameters.select { |p|
|
98
|
-
fields.include?(p)
|
99
|
-
}
|
115
|
+
body_params = request.request_parameters.select { |p| fields.include?(p) }
|
100
116
|
|
101
117
|
# Add query params in place of missing body params, if configured.
|
102
118
|
if self.class.accept_generic_params_as_body_params
|
@@ -113,9 +129,7 @@ module RESTFramework::BaseModelControllerMixin
|
|
113
129
|
end
|
114
130
|
|
115
131
|
# Filter fields in exclude_body_fields.
|
116
|
-
(self.class.exclude_body_fields || []).each
|
117
|
-
body_params.delete(f.to_s)
|
118
|
-
end
|
132
|
+
(self.class.exclude_body_fields || []).each { |f| body_params.delete(f.to_s) }
|
119
133
|
|
120
134
|
body_params
|
121
135
|
end
|
@@ -123,14 +137,6 @@ module RESTFramework::BaseModelControllerMixin
|
|
123
137
|
alias :get_create_params :get_body_params
|
124
138
|
alias :get_update_params :get_body_params
|
125
139
|
|
126
|
-
# Get a record by the primary key from the (non-filtered) recordset.
|
127
|
-
def get_record
|
128
|
-
if pk = params[self.get_model.primary_key]
|
129
|
-
return self.get_recordset.find(pk)
|
130
|
-
end
|
131
|
-
return nil
|
132
|
-
end
|
133
|
-
|
134
140
|
# Get the model for this controller.
|
135
141
|
def get_model(from_get_recordset: false)
|
136
142
|
return @model if instance_variable_defined?(:@model) && @model
|
@@ -164,6 +170,29 @@ module RESTFramework::BaseModelControllerMixin
|
|
164
170
|
|
165
171
|
return nil
|
166
172
|
end
|
173
|
+
|
174
|
+
# Get a single record by primary key or another column, if allowed.
|
175
|
+
def get_record
|
176
|
+
recordset = self.get_recordset
|
177
|
+
find_by_fields = self.get_find_by_fields
|
178
|
+
find_by_key = self.get_model.primary_key
|
179
|
+
|
180
|
+
# Find by another column if it's permitted.
|
181
|
+
if find_by_query_param && params[find_by_query_param].in?(find_by_fields)
|
182
|
+
find_by_key = params[find_by_query_param]
|
183
|
+
end
|
184
|
+
|
185
|
+
# Filter recordset, if configured.
|
186
|
+
if self.filter_recordset_before_find
|
187
|
+
recordset = self.get_filtered_data(recordset)
|
188
|
+
end
|
189
|
+
|
190
|
+
# Return the record.
|
191
|
+
if find_by_value = params[:id] # Route key is always :id by Rails convention.
|
192
|
+
return self.get_recordset.find_by!(find_by_key => find_by_value)
|
193
|
+
end
|
194
|
+
return nil
|
195
|
+
end
|
167
196
|
end
|
168
197
|
|
169
198
|
|
@@ -200,8 +229,8 @@ end
|
|
200
229
|
# Mixin for creating records.
|
201
230
|
module RESTFramework::CreateModelMixin
|
202
231
|
def create
|
203
|
-
if self.get_recordset.respond_to?(:create!) &&
|
204
|
-
# Create with any properties inherited from the recordset
|
232
|
+
if self.get_recordset.respond_to?(:create!) && self.create_from_recordset
|
233
|
+
# Create with any properties inherited from the recordset.
|
205
234
|
@record = self.get_recordset.create!(self.get_create_params)
|
206
235
|
else
|
207
236
|
# Otherwise, perform a "bare" create.
|
@@ -2,6 +2,7 @@
|
|
2
2
|
class RESTFramework::Error < StandardError
|
3
3
|
end
|
4
4
|
|
5
|
+
|
5
6
|
class RESTFramework::NilPassedToAPIResponseError < RESTFramework::Error
|
6
7
|
def message
|
7
8
|
return <<~MSG.split("\n").join(' ')
|
@@ -14,6 +15,7 @@ class RESTFramework::NilPassedToAPIResponseError < RESTFramework::Error
|
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
18
|
+
|
17
19
|
class RESTFramework::UnserializableError < RESTFramework::Error
|
18
20
|
def initialize(object)
|
19
21
|
@object = object
|
@@ -14,7 +14,7 @@ end
|
|
14
14
|
class RESTFramework::ModelFilter < RESTFramework::BaseFilter
|
15
15
|
# Filter params for keys allowed by the current action's filterset_fields/fields config.
|
16
16
|
def _get_filter_params
|
17
|
-
fields = @controller.
|
17
|
+
fields = @controller.send(:get_filterset_fields)
|
18
18
|
return @controller.request.query_parameters.select { |p|
|
19
19
|
fields.include?(p)
|
20
20
|
}.to_h.symbolize_keys # convert from HashWithIndifferentAccess to Hash w/keys
|
@@ -36,17 +36,25 @@ end
|
|
36
36
|
class RESTFramework::ModelOrderingFilter < RESTFramework::BaseFilter
|
37
37
|
# Convert ordering string to an ordering configuration.
|
38
38
|
def _get_ordering
|
39
|
-
return nil
|
39
|
+
return nil if @controller.class.ordering_query_param.blank?
|
40
|
+
ordering_fields = @controller.send(:get_ordering_fields)
|
40
41
|
|
41
42
|
order_string = @controller.params[@controller.class.ordering_query_param]
|
42
43
|
unless order_string.blank?
|
43
|
-
|
44
|
+
ordering = {}
|
45
|
+
order_string.split(',').each do |field|
|
44
46
|
if field[0] == '-'
|
45
|
-
|
47
|
+
column = field[1..-1]
|
48
|
+
direction = :desc
|
46
49
|
else
|
47
|
-
|
50
|
+
column = field
|
51
|
+
direction = :asc
|
48
52
|
end
|
49
|
-
|
53
|
+
if column.in?(ordering_fields)
|
54
|
+
ordering[column.to_sym] = direction
|
55
|
+
end
|
56
|
+
end
|
57
|
+
return ordering
|
50
58
|
end
|
51
59
|
|
52
60
|
return nil
|
@@ -1,26 +1,67 @@
|
|
1
1
|
require 'rails/generators'
|
2
2
|
|
3
3
|
|
4
|
+
# Some projects don't have the inflection "REST" as an acronym, so this is a helper class to prevent
|
5
|
+
# this generator from being namespaced under `r_e_s_t_framework`.
|
6
|
+
# :nocov:
|
7
|
+
class RESTFrameworkCustomGeneratorControllerNamespace < String
|
8
|
+
def camelize
|
9
|
+
return "RESTFramework"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
# :nocov:
|
13
|
+
|
14
|
+
|
4
15
|
class RESTFramework::Generators::ControllerGenerator < Rails::Generators::Base
|
16
|
+
PATH_REGEX = /^\/*([a-z0-9_\/]*[a-z0-9_])(?:[\.a-z\/]*)$/
|
17
|
+
|
5
18
|
desc <<~END
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
`
|
17
|
-
Credit card controller with URLs like /credit_card/debit.
|
18
|
-
Controller: app/controllers/credit_cards_controller.rb
|
19
|
-
Functional Test: test/functional/credit_cards_controller_test.rb
|
20
|
-
Helper: app/helpers/credit_cards_helper.rb
|
19
|
+
Description:
|
20
|
+
Generates a new REST Framework controller.
|
21
|
+
|
22
|
+
Specify the controller as a path, including the module, if needed, like:
|
23
|
+
'parent_module/controller_name'.
|
24
|
+
|
25
|
+
Example:
|
26
|
+
`rails generate rest_framework:controller user_api/groups`
|
27
|
+
|
28
|
+
Generates a controller at `app/controllers/user_api/groups_controller.rb` named
|
29
|
+
`UserApi::GroupsController`.
|
21
30
|
END
|
22
31
|
|
23
|
-
|
24
|
-
|
32
|
+
argument :path, type: :string
|
33
|
+
class_option(
|
34
|
+
:parent_class,
|
35
|
+
type: :string,
|
36
|
+
default: 'ApplicationController',
|
37
|
+
desc: "Inheritance parent",
|
38
|
+
)
|
39
|
+
class_option(
|
40
|
+
:include_base,
|
41
|
+
type: :boolean,
|
42
|
+
default: false,
|
43
|
+
desc: "Include `BaseControllerMixin`, not `ModelControllerMixin`",
|
44
|
+
)
|
45
|
+
|
46
|
+
# Some projects may not have the inflection "REST" as an acronym, which changes this generator to
|
47
|
+
# be namespaced in `r_e_s_t_framework`, which is weird.
|
48
|
+
def self.namespace
|
49
|
+
return RESTFrameworkCustomGeneratorControllerNamespace.new("rest_framework:controller")
|
50
|
+
end
|
51
|
+
|
52
|
+
def create_rest_controller_file
|
53
|
+
unless (path_match = PATH_REGEX.match(self.path))
|
54
|
+
raise StandardError.new("Path isn't correct.")
|
55
|
+
end
|
56
|
+
|
57
|
+
cleaned_path = path_match[1]
|
58
|
+
content = <<~END
|
59
|
+
class #{cleaned_path.camelize}Controller < #{options[:parent_class]}
|
60
|
+
include RESTFramework::#{
|
61
|
+
options[:include_base] ? "BaseControllerMixin" : "ModelControllerMixin"
|
62
|
+
}
|
63
|
+
end
|
64
|
+
END
|
65
|
+
create_file("app/controllers/#{path}_controller.rb", content)
|
25
66
|
end
|
26
67
|
end
|
@@ -6,7 +6,7 @@ module ActionDispatch::Routing
|
|
6
6
|
# Internal helper to take extra_actions hash and convert to a consistent format.
|
7
7
|
protected def _parse_extra_actions(extra_actions)
|
8
8
|
return (extra_actions || {}).map do |k,v|
|
9
|
-
kwargs = {}
|
9
|
+
kwargs = {action: k}
|
10
10
|
path = k
|
11
11
|
|
12
12
|
# Convert structure to path/methods/kwargs.
|
@@ -72,6 +72,16 @@ module ActionDispatch::Routing
|
|
72
72
|
return controller
|
73
73
|
end
|
74
74
|
|
75
|
+
# Interal interface for routing extra actions.
|
76
|
+
protected def _route_extra_actions(actions, &block)
|
77
|
+
actions.each do |action_config|
|
78
|
+
action_config[:methods].each do |m|
|
79
|
+
public_send(m, action_config[:path], **action_config[:kwargs])
|
80
|
+
end
|
81
|
+
yield if block_given?
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
75
85
|
# Internal core implementation of the `rest_resource(s)` router, both singular and plural.
|
76
86
|
# @param default_singular [Boolean] the default plurality of the resource if the plurality is
|
77
87
|
# not otherwise defined by the controller
|
@@ -89,9 +99,11 @@ module ActionDispatch::Routing
|
|
89
99
|
kwargs[:controller] = name unless kwargs[:controller]
|
90
100
|
|
91
101
|
# determine plural/singular resource
|
92
|
-
|
102
|
+
force_singular = kwargs.delete(:force_singular)
|
103
|
+
force_plural = kwargs.delete(:force_plural)
|
104
|
+
if force_singular
|
93
105
|
singular = true
|
94
|
-
elsif
|
106
|
+
elsif force_plural
|
95
107
|
singular = false
|
96
108
|
elsif !controller_class.singleton_controller.nil?
|
97
109
|
singular = controller_class.singleton_controller
|
@@ -100,28 +112,20 @@ module ActionDispatch::Routing
|
|
100
112
|
end
|
101
113
|
resource_method = singular ? :resource : :resources
|
102
114
|
|
103
|
-
#
|
115
|
+
# Call either `resource` or `resources`, passing appropriate modifiers.
|
104
116
|
skip_undefined = kwargs.delete(:skip_undefined) || true
|
105
117
|
skip = controller_class.get_skip_actions(skip_undefined: skip_undefined)
|
106
118
|
public_send(resource_method, name, except: skip, **kwargs) do
|
107
119
|
if controller_class.respond_to?(:extra_member_actions)
|
108
120
|
member do
|
109
121
|
actions = self._parse_extra_actions(controller_class.extra_member_actions)
|
110
|
-
actions
|
111
|
-
action_config[:methods].each do |m|
|
112
|
-
public_send(m, action_config[:path], **action_config[:kwargs])
|
113
|
-
end
|
114
|
-
end
|
122
|
+
_route_extra_actions(actions)
|
115
123
|
end
|
116
124
|
end
|
117
125
|
|
118
126
|
collection do
|
119
127
|
actions = self._parse_extra_actions(controller_class.extra_actions)
|
120
|
-
actions
|
121
|
-
action_config[:methods].each do |m|
|
122
|
-
public_send(m, action_config[:path], **action_config[:kwargs])
|
123
|
-
end
|
124
|
-
end
|
128
|
+
_route_extra_actions(actions)
|
125
129
|
end
|
126
130
|
|
127
131
|
yield if block_given?
|
@@ -145,6 +149,7 @@ module ActionDispatch::Routing
|
|
145
149
|
# Route a controller without the default resourceful paths.
|
146
150
|
def rest_route(name=nil, **kwargs, &block)
|
147
151
|
controller = kwargs.delete(:controller) || name
|
152
|
+
route_root_to = kwargs.delete(:route_root_to)
|
148
153
|
if controller.is_a?(Class)
|
149
154
|
controller_class = controller
|
150
155
|
else
|
@@ -157,42 +162,27 @@ module ActionDispatch::Routing
|
|
157
162
|
# Route actions using the resourceful router, but skip all builtin actions.
|
158
163
|
actions = self._parse_extra_actions(controller_class.extra_actions)
|
159
164
|
public_send(:resource, name, only: [], **kwargs) do
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
end
|
164
|
-
yield if block_given?
|
165
|
+
# Route a root for this resource.
|
166
|
+
if route_root_to
|
167
|
+
get '', action: route_root_to
|
165
168
|
end
|
169
|
+
|
170
|
+
_route_extra_actions(actions, &block)
|
166
171
|
end
|
167
172
|
end
|
168
173
|
|
169
174
|
# Route a controller's `#root` to '/' in the current scope/namespace, along with other actions.
|
170
|
-
# @param name [Symbol] the snake_case name of the controller
|
171
175
|
def rest_root(name=nil, **kwargs, &block)
|
172
176
|
# By default, use RootController#root.
|
173
177
|
root_action = kwargs.delete(:action) || :root
|
174
178
|
controller = kwargs.delete(:controller) || name || :root
|
175
179
|
|
176
|
-
#
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
controller_class = self._get_controller_class(controller, pluralize: false)
|
181
|
-
actions = self._parse_extra_actions(controller_class.extra_actions)
|
182
|
-
actions.each do |action_config|
|
183
|
-
# Add :action unless kwargs defines it.
|
184
|
-
unless action_config[:kwargs].key?(:action)
|
185
|
-
action_config[:kwargs][:action] = action_config[:path]
|
186
|
-
end
|
180
|
+
# Remove path if name is nil (routing to the root of current namespace).
|
181
|
+
unless name
|
182
|
+
kwargs[:path] = ''
|
183
|
+
end
|
187
184
|
|
188
|
-
|
189
|
-
public_send(
|
190
|
-
m,
|
191
|
-
File.join(name.to_s, action_config[:path].to_s),
|
192
|
-
controller: controller,
|
193
|
-
**action_config[:kwargs],
|
194
|
-
)
|
195
|
-
end
|
185
|
+
return rest_route(controller, route_root_to: root_action, **kwargs) do
|
196
186
|
yield if block_given?
|
197
187
|
end
|
198
188
|
end
|
@@ -3,6 +3,10 @@ class RESTFramework::BaseSerializer
|
|
3
3
|
@object = object
|
4
4
|
@controller = controller
|
5
5
|
end
|
6
|
+
|
7
|
+
def serialize
|
8
|
+
raise NotImplementedError
|
9
|
+
end
|
6
10
|
end
|
7
11
|
|
8
12
|
|
@@ -27,7 +31,9 @@ class RESTFramework::NativeSerializer < RESTFramework::BaseSerializer
|
|
27
31
|
# Determine model either explicitly, or by inspecting @object or @controller.
|
28
32
|
@model = model
|
29
33
|
@model ||= @object.class if @object.is_a?(ActiveRecord::Base)
|
30
|
-
@model ||= @object[0].class if
|
34
|
+
@model ||= @object[0].class if (
|
35
|
+
@many && @object.is_a?(Enumerable) && @object.is_a?(ActiveRecord::Base)
|
36
|
+
)
|
31
37
|
@model ||= @controller.send(:get_model) if @controller
|
32
38
|
end
|
33
39
|
|
@@ -115,29 +121,21 @@ class RESTFramework::NativeSerializer < RESTFramework::BaseSerializer
|
|
115
121
|
|
116
122
|
# Allow a serializer instance to be used as a hash directly in a nested serializer config.
|
117
123
|
def [](key)
|
118
|
-
|
119
|
-
@_nested_config = self.get_serializer_config
|
120
|
-
end
|
124
|
+
@_nested_config ||= self.get_serializer_config
|
121
125
|
return @_nested_config[key]
|
122
126
|
end
|
123
127
|
def []=(key, value)
|
124
|
-
|
125
|
-
@_nested_config = self.get_serializer_config
|
126
|
-
end
|
128
|
+
@_nested_config ||= self.get_serializer_config
|
127
129
|
return @_nested_config[key] = value
|
128
130
|
end
|
129
131
|
|
130
132
|
# Allow a serializer class to be used as a hash directly in a nested serializer config.
|
131
133
|
def self.[](key)
|
132
|
-
|
133
|
-
@_nested_config = self.new.get_serializer_config
|
134
|
-
end
|
134
|
+
@_nested_config ||= self.new.get_serializer_config
|
135
135
|
return @_nested_config[key]
|
136
136
|
end
|
137
137
|
def self.[]=(key, value)
|
138
|
-
|
139
|
-
@_nested_config = self.new.get_serializer_config
|
140
|
-
end
|
138
|
+
@_nested_config ||= self.new.get_serializer_config
|
141
139
|
return @_nested_config[key] = value
|
142
140
|
end
|
143
141
|
end
|
@@ -1,35 +1,32 @@
|
|
1
|
+
# Do not use Rails-specific helper methods here (e.g., `blank?`) so the module can run standalone.
|
1
2
|
module RESTFramework
|
2
3
|
module Version
|
3
|
-
|
4
|
+
VERSION_FILEPATH = File.expand_path("../../VERSION", __dir__)
|
4
5
|
|
5
6
|
def self.get_version(skip_git: false)
|
6
|
-
# Return cached @_version, if available.
|
7
|
-
return @_version if @_version
|
8
|
-
|
9
7
|
# First, attempt to get the version from git.
|
10
8
|
unless skip_git
|
11
|
-
|
12
|
-
|
13
|
-
raise "blank version" if version.nil? || version.match(/^\w*$/)
|
14
|
-
# Check for local changes.
|
15
|
-
changes = `git status --porcelain 2>/dev/null`
|
16
|
-
version << '.localchanges' if changes.strip.length > 0
|
17
|
-
return version
|
18
|
-
rescue
|
19
|
-
end
|
9
|
+
version = `git describe --dirty --broken 2>/dev/null`&.strip
|
10
|
+
return version unless !version || version.empty?
|
20
11
|
end
|
21
12
|
|
22
|
-
# Git failed, so try to find a
|
13
|
+
# Git failed or was skipped, so try to find a VERSION file.
|
23
14
|
begin
|
24
|
-
version = File.read(
|
25
|
-
unless version
|
26
|
-
|
27
|
-
end
|
28
|
-
rescue
|
15
|
+
version = File.read(VERSION_FILEPATH)&.strip
|
16
|
+
return version unless !version || version.blank?
|
17
|
+
rescue SystemCallError
|
29
18
|
end
|
30
19
|
|
31
|
-
# No
|
32
|
-
return '
|
20
|
+
# No VERSION file, so version is unknown.
|
21
|
+
return 'unknown'
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.stamp_version
|
25
|
+
File.write(VERSION_FILEPATH, RESTFramework::VERSION)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.unstamp_version
|
29
|
+
File.delete(VERSION_FILEPATH) if File.exist?(VERSION_FILEPATH)
|
33
30
|
end
|
34
31
|
end
|
35
32
|
|
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.3.0
|
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: 2021-
|
11
|
+
date: 2021-04-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -33,12 +33,12 @@ extra_rdoc_files: []
|
|
33
33
|
files:
|
34
34
|
- LICENSE
|
35
35
|
- README.md
|
36
|
+
- VERSION
|
36
37
|
- app/views/layouts/rest_framework.html.erb
|
37
38
|
- app/views/rest_framework/_head.html.erb
|
38
39
|
- app/views/rest_framework/_routes.html.erb
|
39
40
|
- app/views/rest_framework/default.html.erb
|
40
41
|
- lib/rest_framework.rb
|
41
|
-
- lib/rest_framework/VERSION_STAMP
|
42
42
|
- lib/rest_framework/controller_mixins.rb
|
43
43
|
- lib/rest_framework/controller_mixins/base.rb
|
44
44
|
- lib/rest_framework/controller_mixins/models.rb
|
@@ -1 +0,0 @@
|
|
1
|
-
0.2.0
|