rest_framework 1.2.0 → 2.0.0.beta2
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 +109 -41
- data/VERSION +1 -1
- data/lib/rest_framework/controller/actions.rb +256 -0
- data/lib/rest_framework/controller/bulk.rb +15 -10
- data/lib/rest_framework/controller/crud.rb +10 -5
- data/lib/rest_framework/controller/openapi.rb +3 -2
- data/lib/rest_framework/controller.rb +231 -137
- data/lib/rest_framework/errors.rb +18 -1
- data/lib/rest_framework/filters/base_filter.rb +10 -0
- data/lib/rest_framework/filters/ordering_filter.rb +43 -23
- data/lib/rest_framework/filters/query_filter.rb +19 -5
- data/lib/rest_framework/filters/search_filter.rb +8 -8
- data/lib/rest_framework/paginators/page_number_paginator.rb +25 -9
- data/lib/rest_framework/routers.rb +52 -188
- data/lib/rest_framework/serializers/active_model_serializer_adapter_factory.rb +2 -2
- data/lib/rest_framework/serializers/base_serializer.rb +2 -2
- data/lib/rest_framework/serializers/native_serializer.rb +76 -24
- data/lib/rest_framework/utils.rb +32 -70
- data/lib/rest_framework/version.rb +8 -5
- data/lib/rest_framework.rb +7 -38
- metadata +5 -8
- data/lib/rest_framework/mixins/base_controller_mixin.rb +0 -12
- data/lib/rest_framework/mixins/bulk_model_controller_mixin.rb +0 -55
- data/lib/rest_framework/mixins/model_controller_mixin.rb +0 -110
- data/lib/rest_framework/mixins.rb +0 -7
|
@@ -111,25 +111,77 @@ class RESTFramework::Serializers::NativeSerializer < RESTFramework::Serializers:
|
|
|
111
111
|
controller_serializer || @controller.class.native_serializer_config
|
|
112
112
|
end
|
|
113
113
|
|
|
114
|
-
#
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
114
|
+
# The record cap for a collection association (`nil` = unlimited). The default is applied even
|
|
115
|
+
# when the feature is off, so responses are always bounded. `key?` (not `||`) reads the
|
|
116
|
+
# `field_config` override so an explicit `nil` there means unlimited/uncapped rather than falling
|
|
117
|
+
# back to the controller default.
|
|
118
|
+
def _effective_association_limit(association_name, field_config)
|
|
119
|
+
controller = @controller&.class
|
|
120
|
+
|
|
121
|
+
default = field_config.key?(:limit) ?
|
|
122
|
+
field_config[:limit] : controller&.association_limit
|
|
123
|
+
return default unless controller&.enable_association_queries
|
|
124
|
+
|
|
125
|
+
requested = self._requested_association_limit(association_name)
|
|
126
|
+
return default if requested.nil?
|
|
127
|
+
|
|
128
|
+
max = field_config.key?(:limit_max) ?
|
|
129
|
+
field_config[:limit_max] : controller.association_limit_max
|
|
130
|
+
|
|
131
|
+
# `all` means "as many as allowed" — the cap, or unlimited when the cap is `nil`.
|
|
132
|
+
return max if requested == :all
|
|
133
|
+
|
|
134
|
+
max ? [ requested, max ].min : requested
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# `all`, `none`, and `0` all mean "no limit" — `0` is free to reuse as a sentinel since an
|
|
138
|
+
# association is dropped via `except`, not `limit=0`. Anything else must be a plain positive
|
|
139
|
+
# integer, so a nested/array param or junk can't drive the query.
|
|
140
|
+
def _requested_association_limit(association_name)
|
|
141
|
+
return nil unless prefix = @controller.class.association_query_prefix.presence
|
|
142
|
+
|
|
143
|
+
raw = @controller.request&.query_parameters&.[]("#{prefix}.#{association_name}.limit")
|
|
144
|
+
return nil unless raw.is_a?(String)
|
|
145
|
+
|
|
146
|
+
raw = raw.strip
|
|
147
|
+
return :all if raw.in?(%w[all none])
|
|
148
|
+
return nil unless raw.match?(/\A\d+\z/)
|
|
149
|
+
|
|
150
|
+
# The regex guarantees a non-negative integer, so anything but zero is a positive limit.
|
|
151
|
+
limit = raw.to_i
|
|
152
|
+
limit.zero? ? :all : limit
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# The fields to serialize for association `f`, honoring a consumer's `?<prefix>.<f>.fields=`
|
|
156
|
+
# request bounded by the allowlist. Only active when the feature is enabled.
|
|
157
|
+
def _effective_association_fields(association_name, ref, field_config)
|
|
158
|
+
default_fields = field_config[:fields]
|
|
159
|
+
return default_fields unless @controller&.class&.enable_association_queries
|
|
160
|
+
return default_fields if ref.polymorphic? # no single target class to bound the request
|
|
161
|
+
|
|
162
|
+
requested = self._requested_association_fields(association_name)
|
|
163
|
+
return default_fields if requested.blank?
|
|
164
|
+
|
|
165
|
+
# The primary key is always kept so records stay identifiable. `_valid_association_field?` is
|
|
166
|
+
# the last line of defense against leaking a non-serializable or nested-association field.
|
|
167
|
+
allowed = (default_fields + (field_config[:requestable_fields] || [])).uniq
|
|
168
|
+
valid = (requested & allowed).select { |sf| self._valid_association_field?(ref, sf) }
|
|
169
|
+
(Array(ref.klass.primary_key).map(&:to_s) + valid).uniq
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Only a plain scalar string is honored, so a nested-hash/array param can't reach `where`/`split`.
|
|
173
|
+
def _requested_association_fields(association_name)
|
|
174
|
+
return nil unless prefix = @controller.class.association_query_prefix.presence
|
|
175
|
+
|
|
176
|
+
raw = @controller.request&.query_parameters&.[]("#{prefix}.#{association_name}.fields")
|
|
177
|
+
return nil unless raw.is_a?(String)
|
|
178
|
+
|
|
179
|
+
raw.split(",").map { |x| x.strip.presence }.compact
|
|
180
|
+
end
|
|
131
181
|
|
|
132
|
-
|
|
182
|
+
def _valid_association_field?(ref, field)
|
|
183
|
+
field.in?(ref.klass.column_names) ||
|
|
184
|
+
(ref.klass.method_defined?(field) && !ref.klass.reflect_on_association(field.to_sym))
|
|
133
185
|
end
|
|
134
186
|
|
|
135
187
|
# Get a serializer configuration from the controller. `@controller` and `@model` must be set.
|
|
@@ -158,7 +210,7 @@ class RESTFramework::Serializers::NativeSerializer < RESTFramework::Serializers:
|
|
|
158
210
|
elsif ref = reflections[f]
|
|
159
211
|
sub_columns = []
|
|
160
212
|
sub_methods = []
|
|
161
|
-
field_config
|
|
213
|
+
self._effective_association_fields(f, ref, field_config).each do |sf|
|
|
162
214
|
if !ref.polymorphic? && sf.in?(ref.klass.column_names)
|
|
163
215
|
sub_columns << sf
|
|
164
216
|
else
|
|
@@ -169,9 +221,9 @@ class RESTFramework::Serializers::NativeSerializer < RESTFramework::Serializers:
|
|
|
169
221
|
|
|
170
222
|
# Apply certain rules regarding collection associations.
|
|
171
223
|
if ref.collection?
|
|
172
|
-
#
|
|
173
|
-
#
|
|
174
|
-
if limit = self.
|
|
224
|
+
# A finite limit needs a per-record `.limit` query, since eager `includes` can't cap rows
|
|
225
|
+
# per parent; an unlimited (`nil`) association falls through to `includes` preloading.
|
|
226
|
+
if limit = self._effective_association_limit(f, field_config)
|
|
175
227
|
serializer_methods[f] = f
|
|
176
228
|
self.define_singleton_method(f) do |record|
|
|
177
229
|
next record.send(f).limit(limit).as_json(**sub_config)
|
|
@@ -181,7 +233,7 @@ class RESTFramework::Serializers::NativeSerializer < RESTFramework::Serializers:
|
|
|
181
233
|
#
|
|
182
234
|
# # Even though we use a serializer method, if the count will later be added, then put
|
|
183
235
|
# # this field into the includes_map.
|
|
184
|
-
# if @controller.class.
|
|
236
|
+
# if @controller.class.include_association_count
|
|
185
237
|
# includes_map[f] = f.to_sym
|
|
186
238
|
# end
|
|
187
239
|
else
|
|
@@ -190,7 +242,7 @@ class RESTFramework::Serializers::NativeSerializer < RESTFramework::Serializers:
|
|
|
190
242
|
end
|
|
191
243
|
|
|
192
244
|
# If we need to include the association count, then add it here.
|
|
193
|
-
if @controller.class.
|
|
245
|
+
if @controller.class.include_association_count
|
|
194
246
|
method_name = "#{f}.count"
|
|
195
247
|
serializer_methods[method_name] = method_name
|
|
196
248
|
self.define_singleton_method(method_name) do |record|
|
data/lib/rest_framework/utils.rb
CHANGED
|
@@ -1,59 +1,6 @@
|
|
|
1
1
|
module RESTFramework::Utils
|
|
2
2
|
HTTP_VERB_ORDERING = %w[GET POST PUT PATCH DELETE OPTIONS HEAD]
|
|
3
3
|
|
|
4
|
-
# Convert `extra_actions` hash to a consistent format: `{path:, methods:, metadata:, kwargs:}`.
|
|
5
|
-
def self.parse_extra_actions(extra_actions)
|
|
6
|
-
(extra_actions || {}).map { |k, v|
|
|
7
|
-
path = k
|
|
8
|
-
kwargs = {}
|
|
9
|
-
|
|
10
|
-
# Convert structure to path/methods/kwargs.
|
|
11
|
-
if v.is_a?(Hash)
|
|
12
|
-
# Symbolize keys (which also makes a copy so we don't mutate the original).
|
|
13
|
-
v = v.symbolize_keys
|
|
14
|
-
|
|
15
|
-
# Cast method/methods to an array.
|
|
16
|
-
methods = [ v.delete(:methods), v.delete(:method) ].flatten.compact
|
|
17
|
-
|
|
18
|
-
# Override path if it's provided.
|
|
19
|
-
if v.key?(:path)
|
|
20
|
-
path = v.delete(:path)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# Extract metadata, if provided.
|
|
24
|
-
metadata = v.delete(:metadata).presence
|
|
25
|
-
|
|
26
|
-
# Pass any further kwargs to the underlying Rails interface.
|
|
27
|
-
kwargs = v
|
|
28
|
-
else
|
|
29
|
-
methods = [ v ].flatten
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
next [
|
|
33
|
-
k,
|
|
34
|
-
{
|
|
35
|
-
path: path,
|
|
36
|
-
methods: methods,
|
|
37
|
-
metadata: metadata,
|
|
38
|
-
kwargs: kwargs,
|
|
39
|
-
}.compact,
|
|
40
|
-
]
|
|
41
|
-
}.to_h
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def self.get_skipped_builtin_actions(controller_class, singular)
|
|
45
|
-
candidates = (
|
|
46
|
-
RESTFramework::BUILTIN_ACTIONS.keys - (singular ? [ :index ] : [])
|
|
47
|
-
) + RESTFramework::BUILTIN_MEMBER_ACTIONS.keys
|
|
48
|
-
|
|
49
|
-
return candidates unless controller_class.model
|
|
50
|
-
|
|
51
|
-
exclude = controller_class.excluded_actions&.to_set || Set.new
|
|
52
|
-
candidates.reject do |action|
|
|
53
|
-
controller_class.method_defined?(action) && !exclude.include?(action)
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
4
|
# Get the first route pattern which matches the given request.
|
|
58
5
|
def self.get_request_route(application_routes, request)
|
|
59
6
|
# Prefer the route already resolved by the router to avoid an expensive `recognize` call. This
|
|
@@ -172,9 +119,8 @@ module RESTFramework::Utils
|
|
|
172
119
|
parsed_fields.map(&:to_s)
|
|
173
120
|
end
|
|
174
121
|
|
|
175
|
-
# Get the fields for a given model, including not just columns (which includes
|
|
176
|
-
#
|
|
177
|
-
# strings, not symbols.
|
|
122
|
+
# Get the fields for a given model, including not just columns (which includes foreign keys), but
|
|
123
|
+
# also associations. Note that we always return an array of strings, not symbols.
|
|
178
124
|
def self.fields_for(model, exclude_associations:, action_text:, active_storage:)
|
|
179
125
|
foreign_keys = model.reflect_on_all_associations(:belongs_to).map(&:foreign_key)
|
|
180
126
|
base_fields = model.column_names.reject { |c| c.in?(foreign_keys) }
|
|
@@ -208,23 +154,23 @@ module RESTFramework::Utils
|
|
|
208
154
|
base_fields + associations + atf + asf
|
|
209
155
|
end
|
|
210
156
|
|
|
211
|
-
# Get the
|
|
212
|
-
def self.
|
|
157
|
+
# Get the association's fields that may be serialized and filtered/ordered for a reflection.
|
|
158
|
+
def self.association_fields_for(ref)
|
|
213
159
|
if !ref.polymorphic? && model = ref.klass
|
|
214
|
-
|
|
160
|
+
fields = [ model.primary_key ].flatten.compact
|
|
215
161
|
label_fields = RESTFramework.config.label_fields
|
|
216
162
|
|
|
217
163
|
# Preferably find a database column to use as label.
|
|
218
164
|
if match = label_fields.find { |f| f.in?(model.column_names) }
|
|
219
|
-
return
|
|
165
|
+
return fields + [ match ]
|
|
220
166
|
end
|
|
221
167
|
|
|
222
168
|
# Otherwise, find a method.
|
|
223
169
|
if match = label_fields.find { |f| model.method_defined?(f) }
|
|
224
|
-
return
|
|
170
|
+
return fields + [ match ]
|
|
225
171
|
end
|
|
226
172
|
|
|
227
|
-
return
|
|
173
|
+
return fields
|
|
228
174
|
end
|
|
229
175
|
|
|
230
176
|
[ "id", "name" ]
|
|
@@ -243,6 +189,30 @@ module RESTFramework::Utils
|
|
|
243
189
|
nil
|
|
244
190
|
end
|
|
245
191
|
|
|
192
|
+
# Find the REST controller for `model` at the same namespace level as `current_controller`, e.g.
|
|
193
|
+
# `Api::Demo::MoviesController` + `Genre` => `Api::Demo::GenresController`, or `nil` if none. The
|
|
194
|
+
# `model` match guards against trusting a same-named controller for a different model.
|
|
195
|
+
def self.controller_for_model(current_controller, model)
|
|
196
|
+
return nil unless model && (base_name = current_controller.name)
|
|
197
|
+
|
|
198
|
+
namespace = base_name.deconstantize
|
|
199
|
+
model_name = model.model_name
|
|
200
|
+
|
|
201
|
+
# Plural for a collection controller, singular for a singular-resource one.
|
|
202
|
+
[ model_name.plural, model_name.singular ].each do |name|
|
|
203
|
+
candidate_name = "#{name.camelize}Controller"
|
|
204
|
+
candidate_name = "#{namespace}::#{candidate_name}" if namespace.present?
|
|
205
|
+
|
|
206
|
+
candidate = candidate_name.safe_constantize
|
|
207
|
+
next unless candidate.is_a?(Class) && candidate.include?(RESTFramework::Controller)
|
|
208
|
+
next unless candidate.model == model
|
|
209
|
+
|
|
210
|
+
return candidate
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
nil
|
|
214
|
+
end
|
|
215
|
+
|
|
246
216
|
# Wrap a serializer with an adapter if it is an ActiveModel::Serializer.
|
|
247
217
|
def self.wrap_ams(s)
|
|
248
218
|
if defined?(ActiveModel::Serializer) && (s < ActiveModel::Serializer)
|
|
@@ -251,12 +221,4 @@ module RESTFramework::Utils
|
|
|
251
221
|
|
|
252
222
|
s
|
|
253
223
|
end
|
|
254
|
-
|
|
255
|
-
# Used for deprecated mixins that rely on model being determined from the controller name.
|
|
256
|
-
def self.get_model(controller_class)
|
|
257
|
-
begin
|
|
258
|
-
controller_class.name.demodulize.chomp("Controller").singularize.constantize
|
|
259
|
-
rescue NameError
|
|
260
|
-
end
|
|
261
|
-
end
|
|
262
224
|
end
|
|
@@ -22,11 +22,14 @@ module RESTFramework
|
|
|
22
22
|
UNKNOWN
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
def self.stamp_version
|
|
26
|
-
#
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
def self.stamp_version(version = nil)
|
|
26
|
+
# Stamp the given version into the VERSION file, deriving it from git when none is provided.
|
|
27
|
+
# Returns the stamped version so callers don't rely on the (require-time) `VERSION` constant.
|
|
28
|
+
version ||= self.get_version
|
|
29
|
+
if version != UNKNOWN
|
|
30
|
+
File.write(VERSION_FILEPATH, version)
|
|
29
31
|
end
|
|
32
|
+
version
|
|
30
33
|
end
|
|
31
34
|
|
|
32
35
|
def self.unstamp_version
|
|
@@ -34,5 +37,5 @@ module RESTFramework
|
|
|
34
37
|
end
|
|
35
38
|
end
|
|
36
39
|
|
|
37
|
-
VERSION = Version.get_version
|
|
40
|
+
VERSION = Version.get_version(skip_git: true)
|
|
38
41
|
end
|
data/lib/rest_framework.rb
CHANGED
|
@@ -1,26 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module RESTFramework
|
|
4
|
-
BUILTIN_FORM_ACTIONS = [ :new, :edit ].freeze
|
|
5
|
-
BUILTIN_ACTIONS = {
|
|
6
|
-
index: :get,
|
|
7
|
-
new: :get,
|
|
8
|
-
create: :post,
|
|
9
|
-
}.freeze
|
|
10
|
-
BUILTIN_MEMBER_ACTIONS = {
|
|
11
|
-
show: :get,
|
|
12
|
-
edit: :get,
|
|
13
|
-
update: [ :put, :patch ].freeze,
|
|
14
|
-
destroy: :delete,
|
|
15
|
-
}.freeze
|
|
16
|
-
RRF_BUILTIN_ACTIONS = {
|
|
17
|
-
options: :options,
|
|
18
|
-
}.freeze
|
|
19
|
-
RRF_BUILTIN_BULK_ACTIONS = {
|
|
20
|
-
update_all: [ :put, :patch ].freeze,
|
|
21
|
-
destroy_all: :delete,
|
|
22
|
-
}.freeze
|
|
23
|
-
|
|
24
4
|
# Storage for extra routes and associated metadata.
|
|
25
5
|
EXTRA_ACTION_ROUTES = Set.new
|
|
26
6
|
ROUTE_METADATA = {}
|
|
@@ -47,6 +27,7 @@ module RESTFramework
|
|
|
47
27
|
# Bootstrap Icons
|
|
48
28
|
"bootstrap-icons.min.css" => {
|
|
49
29
|
url: "https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css",
|
|
30
|
+
sri: "sha384-XGjxtQfXaH2tnPFa9x+ruJTuLE3Aa6LhHSWRr1XeTyhezb4abCG4ccI5AkVDxqC+",
|
|
50
31
|
inline_fonts: true,
|
|
51
32
|
},
|
|
52
33
|
|
|
@@ -74,19 +55,23 @@ module RESTFramework
|
|
|
74
55
|
extra_tag_attrs: { class: "rrf-light-mode" },
|
|
75
56
|
},
|
|
76
57
|
|
|
77
|
-
# NeatJSON
|
|
58
|
+
# NeatJSON. The package publishes no minified build; jsdelivr's `neatjson.min.js` is synthesized
|
|
59
|
+
# on the fly (so its bytes/SRI aren't stable), so we pin the published `neatjson.js` instead.
|
|
78
60
|
"neatjson.min.js" => {
|
|
79
|
-
url: "https://cdn.jsdelivr.net/npm/neatjson@0.10.6/javascript/neatjson.
|
|
61
|
+
url: "https://cdn.jsdelivr.net/npm/neatjson@0.10.6/javascript/neatjson.js",
|
|
62
|
+
sri: "sha384-7yRMvyGBuBnnlsgFwUDx7wY7Y/kXt7Irg5xppXVAI0yp3R0870lWaXNP/JE2rbFA",
|
|
80
63
|
exclude_from_docs: true,
|
|
81
64
|
},
|
|
82
65
|
|
|
83
66
|
# Trix
|
|
84
67
|
"trix.min.css" => {
|
|
85
68
|
url: "https://unpkg.com/trix@2.0.8/dist/trix.css",
|
|
69
|
+
sri: "sha384-Cgg84c/W0Q5VrTzc4ITmV88Ocx4Pn1YlTXPvSTJjX6+lxJRLYrZ4chaighxlqOY1",
|
|
86
70
|
exclude_from_docs: true,
|
|
87
71
|
},
|
|
88
72
|
"trix.min.js" => {
|
|
89
73
|
url: "https://unpkg.com/trix@2.0.8/dist/trix.umd.min.js",
|
|
74
|
+
sri: "sha384-Ki3zDe3whjAHK/GOksrYLGCU8m0SkmiJQ4Kqm3jQlM3YCl2hFBf17s9bzjVYmXWX",
|
|
90
75
|
exclude_from_docs: true,
|
|
91
76
|
},
|
|
92
77
|
}.map { |name, cfg|
|
|
@@ -149,19 +134,6 @@ module RESTFramework
|
|
|
149
134
|
# Permits use of `render(api: obj)` syntax over `render_api(obj)`; `true` by default.
|
|
150
135
|
attr_accessor :register_api_renderer
|
|
151
136
|
|
|
152
|
-
# Run `rrf_finalize` on controllers automatically using a `TracePoint` hook. This is `true` by
|
|
153
|
-
# default, and can be disabled for performance, and must be global because we have to determine
|
|
154
|
-
# this before any controller-specific configuration is set. If this is set to `false`, then you
|
|
155
|
-
# must manually call `rrf_finalize` after any configuration on each controller that needs to
|
|
156
|
-
# participate in:
|
|
157
|
-
# - Model delegation, for the helper methods to be defined dynamically.
|
|
158
|
-
# - Websockets, for `::Channel` class to be defined dynamically.
|
|
159
|
-
# - Controller configuration freezing.
|
|
160
|
-
attr_accessor :auto_finalize
|
|
161
|
-
|
|
162
|
-
# Freeze configuration attributes during finalization to prevent accidental mutation.
|
|
163
|
-
attr_accessor :freeze_config
|
|
164
|
-
|
|
165
137
|
# Specify reverse association tables that are typically very large, and therefore should not be
|
|
166
138
|
# added to fields by default.
|
|
167
139
|
attr_accessor :large_reverse_association_tables
|
|
@@ -188,8 +160,6 @@ module RESTFramework
|
|
|
188
160
|
|
|
189
161
|
def initialize
|
|
190
162
|
self.register_api_renderer = true
|
|
191
|
-
self.auto_finalize = true
|
|
192
|
-
self.freeze_config = true
|
|
193
163
|
|
|
194
164
|
self.show_backtrace = Rails.env.development?
|
|
195
165
|
|
|
@@ -221,7 +191,6 @@ end
|
|
|
221
191
|
require_relative "rest_framework/engine"
|
|
222
192
|
require_relative "rest_framework/errors"
|
|
223
193
|
require_relative "rest_framework/filters"
|
|
224
|
-
require_relative "rest_framework/mixins"
|
|
225
194
|
require_relative "rest_framework/paginators"
|
|
226
195
|
require_relative "rest_framework/routers"
|
|
227
196
|
require_relative "rest_framework/serializers"
|
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:
|
|
4
|
+
version: 2.0.0.beta2
|
|
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: 2026-
|
|
11
|
+
date: 2026-07-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -55,6 +55,7 @@ files:
|
|
|
55
55
|
- app/views/rest_framework/routes_and_forms/routes/_route.html.erb
|
|
56
56
|
- lib/rest_framework.rb
|
|
57
57
|
- lib/rest_framework/controller.rb
|
|
58
|
+
- lib/rest_framework/controller/actions.rb
|
|
58
59
|
- lib/rest_framework/controller/bulk.rb
|
|
59
60
|
- lib/rest_framework/controller/crud.rb
|
|
60
61
|
- lib/rest_framework/controller/openapi.rb
|
|
@@ -66,10 +67,6 @@ files:
|
|
|
66
67
|
- lib/rest_framework/filters/query_filter.rb
|
|
67
68
|
- lib/rest_framework/filters/ransack_filter.rb
|
|
68
69
|
- lib/rest_framework/filters/search_filter.rb
|
|
69
|
-
- lib/rest_framework/mixins.rb
|
|
70
|
-
- lib/rest_framework/mixins/base_controller_mixin.rb
|
|
71
|
-
- lib/rest_framework/mixins/bulk_model_controller_mixin.rb
|
|
72
|
-
- lib/rest_framework/mixins/model_controller_mixin.rb
|
|
73
70
|
- lib/rest_framework/paginators.rb
|
|
74
71
|
- lib/rest_framework/paginators/base_paginator.rb
|
|
75
72
|
- lib/rest_framework/paginators/page_number_paginator.rb
|
|
@@ -101,9 +98,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
101
98
|
version: 2.7.5
|
|
102
99
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
100
|
requirements:
|
|
104
|
-
- - "
|
|
101
|
+
- - ">"
|
|
105
102
|
- !ruby/object:Gem::Version
|
|
106
|
-
version:
|
|
103
|
+
version: 1.3.1
|
|
107
104
|
requirements: []
|
|
108
105
|
rubygems_version: 3.4.10
|
|
109
106
|
signing_key:
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
module RESTFramework::Mixins::BaseControllerMixin
|
|
2
|
-
def self.included(base)
|
|
3
|
-
RESTFramework.deprecator.warn(
|
|
4
|
-
"BaseControllerMixin is deprecated; use RESTFramework::Controller instead.",
|
|
5
|
-
)
|
|
6
|
-
|
|
7
|
-
base.include(RESTFramework::Controller)
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
# Alias for convenience.
|
|
12
|
-
RESTFramework::BaseControllerMixin = RESTFramework::Mixins::BaseControllerMixin
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
module RESTFramework::Mixins::BulkCreateModelMixin
|
|
2
|
-
def self.included(base)
|
|
3
|
-
RESTFramework.deprecator.warn(<<~TXT).squish
|
|
4
|
-
BulkCreateModelMixin is deprecated; set the `bulk = true` class attribute instead.
|
|
5
|
-
TXT
|
|
6
|
-
|
|
7
|
-
base.bulk = true
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
# Mixin for updating records in bulk.
|
|
12
|
-
module RESTFramework::Mixins::BulkUpdateModelMixin
|
|
13
|
-
def self.included(base)
|
|
14
|
-
RESTFramework.deprecator.warn(<<~TXT).squish
|
|
15
|
-
BulkUpdateModelMixin is deprecated; set the `bulk = true`, and `excluded_actions` class
|
|
16
|
-
attributes instead.
|
|
17
|
-
TXT
|
|
18
|
-
|
|
19
|
-
base.bulk = true
|
|
20
|
-
base.excluded_actions = (base.excluded_actions - [ :update_all ]).freeze
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# Mixin for destroying records in bulk.
|
|
25
|
-
module RESTFramework::Mixins::BulkDestroyModelMixin
|
|
26
|
-
def self.included(base)
|
|
27
|
-
RESTFramework.deprecator.warn(<<~TXT).squish
|
|
28
|
-
BulkDestroyModelMixin is deprecated; set the `bulk = true`, and `excluded_actions` class
|
|
29
|
-
attributes instead.
|
|
30
|
-
TXT
|
|
31
|
-
|
|
32
|
-
base.bulk = true
|
|
33
|
-
base.excluded_actions = (base.excluded_actions - [ :destroy_all ]).freeze
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Mixin that includes all the CRUD bulk mixins.
|
|
38
|
-
module RESTFramework::Mixins::BulkModelControllerMixin
|
|
39
|
-
def self.included(base)
|
|
40
|
-
RESTFramework.deprecator.warn(<<~TXT).squish
|
|
41
|
-
BulkModelControllerMixin is deprecated; use RESTFramework::Controller and set the `model` and
|
|
42
|
-
`bulk = true` class attributes instead.
|
|
43
|
-
TXT
|
|
44
|
-
|
|
45
|
-
base.include(RESTFramework::Controller)
|
|
46
|
-
base.model = RESTFramework::Utils.get_model(base)
|
|
47
|
-
base.bulk = true
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# Aliases for convenience.
|
|
52
|
-
RESTFramework::BulkCreateModelMixin = RESTFramework::Mixins::BulkCreateModelMixin
|
|
53
|
-
RESTFramework::BulkUpdateModelMixin = RESTFramework::Mixins::BulkUpdateModelMixin
|
|
54
|
-
RESTFramework::BulkDestroyModelMixin = RESTFramework::Mixins::BulkDestroyModelMixin
|
|
55
|
-
RESTFramework::BulkModelControllerMixin = RESTFramework::Mixins::BulkModelControllerMixin
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
module RESTFramework::Mixins::BaseModelControllerMixin
|
|
2
|
-
def self.included(base)
|
|
3
|
-
RESTFramework.deprecator.warn(<<~TXT).squish
|
|
4
|
-
BaseModelControllerMixin is deprecated; use RESTFramework::Controller and set the `model` and
|
|
5
|
-
`excluded_actions` class attributes instead.
|
|
6
|
-
TXT
|
|
7
|
-
|
|
8
|
-
base.include(RESTFramework::Controller)
|
|
9
|
-
base.model = RESTFramework::Utils.get_model(base)
|
|
10
|
-
base.excluded_actions = [
|
|
11
|
-
:index, :show, :create, :update, :destroy, :update_all, :destroy_all
|
|
12
|
-
].freeze
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
module RESTFramework::Mixins::ListModelMixin
|
|
17
|
-
def self.included(base)
|
|
18
|
-
RESTFramework.deprecator.warn(
|
|
19
|
-
"ListModelMixin is deprecated; set the `excluded_actions` class attribute instead.",
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
if base.excluded_actions
|
|
23
|
-
base.excluded_actions = (base.excluded_actions - [ :index ]).freeze
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
module RESTFramework::Mixins::ShowModelMixin
|
|
29
|
-
def self.included(base)
|
|
30
|
-
RESTFramework.deprecator.warn(
|
|
31
|
-
"ShowModelMixin is deprecated; set the `excluded_actions` class attribute instead.",
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
if base.excluded_actions
|
|
35
|
-
base.excluded_actions = (base.excluded_actions - [ :show ]).freeze
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
module RESTFramework::Mixins::CreateModelMixin
|
|
41
|
-
def self.included(base)
|
|
42
|
-
RESTFramework.deprecator.warn(
|
|
43
|
-
"CreateModelMixin is deprecated; set the `excluded_actions` class attribute instead.",
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
if base.excluded_actions
|
|
47
|
-
base.excluded_actions = (base.excluded_actions - [ :create ]).freeze
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
module RESTFramework::Mixins::UpdateModelMixin
|
|
53
|
-
def self.included(base)
|
|
54
|
-
RESTFramework.deprecator.warn(
|
|
55
|
-
"UpdateModelMixin is deprecated; set the `excluded_actions` class attribute instead.",
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
if base.excluded_actions
|
|
59
|
-
base.excluded_actions = (base.excluded_actions - [ :update ]).freeze
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
module RESTFramework::Mixins::DestroyModelMixin
|
|
65
|
-
def self.included(base)
|
|
66
|
-
RESTFramework.deprecator.warn(
|
|
67
|
-
"DestroyModelMixin is deprecated; set the `excluded_actions` class attribute instead.",
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
if base.excluded_actions
|
|
71
|
-
base.excluded_actions = (base.excluded_actions - [ :destroy ]).freeze
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
module RESTFramework::Mixins::ReadOnlyModelControllerMixin
|
|
77
|
-
def self.included(base)
|
|
78
|
-
RESTFramework.deprecator.warn(<<~TXT).squish
|
|
79
|
-
ReadOnlyModelControllerMixin is deprecated; use RESTFramework::Controller and set the `model`
|
|
80
|
-
and `excluded_actions` class attributes instead.
|
|
81
|
-
TXT
|
|
82
|
-
|
|
83
|
-
base.include(RESTFramework::Controller)
|
|
84
|
-
base.model = RESTFramework::Utils.get_model(base)
|
|
85
|
-
base.excluded_actions = [ :create, :update, :destroy, :update_all, :destroy_all ].freeze
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
module RESTFramework::Mixins::ModelControllerMixin
|
|
90
|
-
def self.included(base)
|
|
91
|
-
RESTFramework.deprecator.warn(<<~TXT).squish
|
|
92
|
-
ModelControllerMixin is deprecated; use RESTFramework::Controller and set the `model` class
|
|
93
|
-
attribute instead.
|
|
94
|
-
TXT
|
|
95
|
-
|
|
96
|
-
base.include(RESTFramework::Controller)
|
|
97
|
-
base.model = RESTFramework::Utils.get_model(base)
|
|
98
|
-
base.excluded_actions = nil
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
# Aliases for convenience.
|
|
103
|
-
RESTFramework::BaseModelControllerMixin = RESTFramework::Mixins::BaseModelControllerMixin
|
|
104
|
-
RESTFramework::ListModelMixin = RESTFramework::Mixins::ListModelMixin
|
|
105
|
-
RESTFramework::ShowModelMixin = RESTFramework::Mixins::ShowModelMixin
|
|
106
|
-
RESTFramework::CreateModelMixin = RESTFramework::Mixins::CreateModelMixin
|
|
107
|
-
RESTFramework::UpdateModelMixin = RESTFramework::Mixins::UpdateModelMixin
|
|
108
|
-
RESTFramework::DestroyModelMixin = RESTFramework::Mixins::DestroyModelMixin
|
|
109
|
-
RESTFramework::ReadOnlyModelControllerMixin = RESTFramework::Mixins::ReadOnlyModelControllerMixin
|
|
110
|
-
RESTFramework::ModelControllerMixin = RESTFramework::Mixins::ModelControllerMixin
|