rest_framework 2.0.0.beta1 → 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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 639dcc597e17e5148cde3f7511637913be7b431899f59a5cc7f504533969233e
|
|
4
|
+
data.tar.gz: 0c732ab6c80f9c06b29e4a30e29087ff4fa65206df15b7826ffd9f0d2781b774
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 656e302db2252a27a30508e1f5c1d2caf2d603288d4ca3e2ec0995355a4a6501b18bc8320463a17113568a562ead98c3896c949a00aa03cc83a6c71f2f62d738
|
|
7
|
+
data.tar.gz: f760d0140360ca1856dca0ab87b8de1903e09fd7cc442c1b40c9150b7abaf312f43ae67a52a5d0881af9e1f98489a074a82ebaef87b527c99e6e8f7175c67740
|
data/README.md
CHANGED
|
@@ -202,8 +202,10 @@ changes; the migration checklist that follows walks through updating an existing
|
|
|
202
202
|
- **Delegated actions wrap their result under a `return` key**, and raise on a missing or non-public
|
|
203
203
|
target instead of silently 404-ing.
|
|
204
204
|
- **Removed** `rrf_finalize` and the `auto_finalize` / `freeze_config` hooks.
|
|
205
|
-
- **Security hardening** —
|
|
206
|
-
|
|
205
|
+
- **Security hardening** — `find_by`, filtering, ordering, and search are scoped to serialized,
|
|
206
|
+
non-`write_only` fields (so hidden/secret columns can't be used as lookup/enumeration keys), plus
|
|
207
|
+
per-element read-only stripping on bulk writes, an ordering-oracle fix, sanitized
|
|
208
|
+
`StatementInvalid` messages, and safer query-filter parsing.
|
|
207
209
|
|
|
208
210
|
### Migrating from Older Versions
|
|
209
211
|
|
|
@@ -217,8 +219,8 @@ See the guide for details on each item.
|
|
|
217
219
|
- [ ] Render custom actions with `render(api: ...)`, replacing the older `api_response(...)` /
|
|
218
220
|
`render_api(...)`.
|
|
219
221
|
- [ ] Replace `rest_resource` / `rest_resources` / `rest_root` with `rest_route`.
|
|
220
|
-
|
|
221
|
-
|
|
222
|
+
- [ ] Fold any dedicated root controller into the namespace's base controller, which now serves the
|
|
223
|
+
root via `index_content` (the standalone `root` action and `rest_root` are gone).
|
|
222
224
|
- [ ] Rename `singleton_controller` → `singular`.
|
|
223
225
|
- [ ] Remove `rrf_finalize` calls and the `auto_finalize` / `freeze_config` config (all gone).
|
|
224
226
|
- [ ] Expect paginated `index` responses by default (`self.paginator_class = nil` restores a bare
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.0.0.
|
|
1
|
+
2.0.0.beta2
|
|
@@ -253,33 +253,29 @@ module RESTFramework::Controller
|
|
|
253
253
|
self.model&.human_attribute_name(s, default: default_title) || default_title
|
|
254
254
|
end
|
|
255
255
|
|
|
256
|
-
#
|
|
257
|
-
#
|
|
258
|
-
def get_fields
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
if input_fields.is_a?(Hash)
|
|
263
|
-
return RESTFramework::Utils.parse_fields_hash(
|
|
264
|
-
input_fields,
|
|
256
|
+
# Resolve the `fields` config to an array of strings. Memoized, since `fields` and the flags it
|
|
257
|
+
# depends on are class-level config fixed at load time.
|
|
258
|
+
def get_fields
|
|
259
|
+
@get_fields ||= if self.fields.is_a?(Hash)
|
|
260
|
+
RESTFramework::Utils.parse_fields_hash(
|
|
261
|
+
self.fields,
|
|
265
262
|
self.model,
|
|
266
263
|
exclude_associations: self.exclude_associations,
|
|
267
264
|
action_text: self.enable_action_text,
|
|
268
265
|
active_storage: self.enable_active_storage,
|
|
269
266
|
)
|
|
270
|
-
elsif
|
|
271
|
-
|
|
272
|
-
|
|
267
|
+
elsif self.fields
|
|
268
|
+
self.fields.map(&:to_s)
|
|
269
|
+
elsif self.model
|
|
270
|
+
RESTFramework::Utils.fields_for(
|
|
273
271
|
self.model,
|
|
274
272
|
exclude_associations: self.exclude_associations,
|
|
275
273
|
action_text: self.enable_action_text,
|
|
276
274
|
active_storage: self.enable_active_storage,
|
|
277
|
-
)
|
|
278
|
-
|
|
279
|
-
|
|
275
|
+
)
|
|
276
|
+
else
|
|
277
|
+
[]
|
|
280
278
|
end
|
|
281
|
-
|
|
282
|
-
input_fields
|
|
283
279
|
end
|
|
284
280
|
|
|
285
281
|
# Get a full field configuration, including defaults and inferred values.
|
|
@@ -647,7 +643,27 @@ module RESTFramework::Controller
|
|
|
647
643
|
end
|
|
648
644
|
|
|
649
645
|
def get_fields
|
|
650
|
-
self.class.get_fields
|
|
646
|
+
self.class.get_fields
|
|
647
|
+
end
|
|
648
|
+
|
|
649
|
+
def readable_fields
|
|
650
|
+
cfg = self.class.field_configuration
|
|
651
|
+
self.get_fields.reject { |f| cfg[f]&.[](:write_only) }
|
|
652
|
+
end
|
|
653
|
+
|
|
654
|
+
# `readable_fields` restricted to real columns, for query surfaces that build SQL directly
|
|
655
|
+
# (find_by, search) and would raise on a virtual/method field.
|
|
656
|
+
def readable_columns
|
|
657
|
+
self.readable_fields & self.class.model.column_names
|
|
658
|
+
end
|
|
659
|
+
|
|
660
|
+
# `readable_fields` restricted to columns and associations, for surfaces that also resolve dotted
|
|
661
|
+
# `association.sub_field` paths (filtering, ordering). Excludes virtual/method fields, which have
|
|
662
|
+
# no column to order or filter by.
|
|
663
|
+
def readable_columns_or_associations
|
|
664
|
+
cfg = self.class.field_configuration
|
|
665
|
+
columns = self.class.model.column_names
|
|
666
|
+
self.readable_fields.select { |f| f.in?(columns) || cfg[f]&.[](:kind) == "association" }
|
|
651
667
|
end
|
|
652
668
|
|
|
653
669
|
# Get a hash of strong parameters for the current action.
|
|
@@ -657,7 +673,8 @@ module RESTFramework::Controller
|
|
|
657
673
|
@_get_allowed_parameters = self.class.allowed_parameters
|
|
658
674
|
return @_get_allowed_parameters if @_get_allowed_parameters
|
|
659
675
|
|
|
660
|
-
# Assemble strong parameters.
|
|
676
|
+
# Assemble strong parameters. Read-only fields are permitted here and stripped later per-action
|
|
677
|
+
# by `_rrf_strip_read_only_fields` (which keeps the primary key on bulk update to find records).
|
|
661
678
|
variations = []
|
|
662
679
|
hash_variations = {}
|
|
663
680
|
reflections = self.class.model.reflections
|
|
@@ -868,9 +885,10 @@ module RESTFramework::Controller
|
|
|
868
885
|
# Find by another column if it's permitted.
|
|
869
886
|
if find_by_param = self.class.find_by_query_param.presence
|
|
870
887
|
if find_by = request.query_parameters[find_by_param].presence
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
)
|
|
888
|
+
# Default to readable columns: excluding write_only keeps hidden values from being used as
|
|
889
|
+
# lookup keys, and restricting to real columns keeps virtual/method fields from reaching a
|
|
890
|
+
# doomed `find_by(<not a column>)` (which would raise on the DB).
|
|
891
|
+
find_by_fields = self.class.find_by_fields&.map(&:to_s) || self.readable_columns
|
|
874
892
|
|
|
875
893
|
# A `find_by` was explicitly requested, so it must be a permitted field.
|
|
876
894
|
raise ActiveRecord::RecordNotFound unless find_by.in?(find_by_fields)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# A filter backend which handles ordering of the recordset.
|
|
2
2
|
class RESTFramework::Filters::OrderingFilter < RESTFramework::Filters::BaseFilter
|
|
3
3
|
def _get_fields
|
|
4
|
-
|
|
4
|
+
# Always return a list of strings; `@controller.readable_columns_or_associations` already does.
|
|
5
|
+
@controller.class.ordering_fields&.map(&:to_s) || @controller.readable_columns_or_associations
|
|
5
6
|
end
|
|
6
7
|
|
|
7
8
|
# Convert the ordering param into an `[ordering, references]` pair: the ordering config for
|
|
@@ -43,8 +43,8 @@ class RESTFramework::Filters::QueryFilter < RESTFramework::Filters::BaseFilter
|
|
|
43
43
|
ARRAY_PREDICATES = %i[in not].freeze
|
|
44
44
|
|
|
45
45
|
def _get_fields
|
|
46
|
-
# Always return a list of strings; `@controller.
|
|
47
|
-
@controller.class.filter_fields&.map(&:to_s) || @controller.
|
|
46
|
+
# Always return a list of strings; `@controller.readable_columns_or_associations` already does.
|
|
47
|
+
@controller.class.filter_fields&.map(&:to_s) || @controller.readable_columns_or_associations
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
# Helper to find a variation of a field using a predicate. For example, there could be a field
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
class RESTFramework::Filters::SearchFilter < RESTFramework::Filters::BaseFilter
|
|
2
2
|
def _get_fields
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
columns = @controller.class.model.column_names
|
|
8
|
-
@controller.get_fields.select { |f|
|
|
9
|
-
f.in?(RESTFramework.config.search_columns) && f.in?(columns)
|
|
10
|
-
}
|
|
3
|
+
# Always return a list of strings; `@controller.readable_columns` already does.
|
|
4
|
+
@controller.class.search_fields&.map(&:to_s) || (
|
|
5
|
+
@controller.readable_columns & RESTFramework.config.search_columns
|
|
6
|
+
)
|
|
11
7
|
end
|
|
12
8
|
|
|
13
9
|
# Filter data according to the request query parameters.
|