Class: RESTFramework::Filters::OrderingFilter
- Inherits:
-
BaseFilter
- Object
- BaseFilter
- RESTFramework::Filters::OrderingFilter
- Defined in:
- lib/rest_framework/filters/ordering_filter.rb
Overview
A filter backend which handles ordering of the recordset.
Instance Method Summary collapse
- #_get_fields ⇒ Object
-
#_get_ordering ⇒ Object
Convert the ordering param into an
[ordering, references]pair: the ordering config fororder/reorder, and the association names that must be joined for it to resolve. -
#filter_data(data) ⇒ Object
Order data according to the request query parameters.
Methods inherited from BaseFilter
#_polymorphic_columns, _safe_query_value?, #initialize
Constructor Details
This class inherits a constructor from RESTFramework::Filters::BaseFilter
Instance Method Details
#_get_fields ⇒ Object
3 4 5 6 |
# File 'lib/rest_framework/filters/ordering_filter.rb', line 3 def _get_fields # Always return a list of strings; `@controller.readable_columns_or_associations` already does. @controller.class.ordering_fields&.map(&:to_s) || @controller.readable_columns_or_associations end |
#_get_ordering ⇒ Object
Convert the ordering param into an [ordering, references] pair: the ordering config for
order/reorder, and the association names that must be joined for it to resolve.
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/rest_framework/filters/ordering_filter.rb', line 10 def _get_ordering return nil unless param = @controller.class.ordering_query_param.presence # Ensure ordering_fields are strings since the split param will be strings. fields = self._get_fields poly_columns = self._polymorphic_columns(@controller.class.ordering_fields) order_string = @controller.request.query_parameters[param] # Reject nested-hash inputs like `?ordering[evil]=x` (Rack parses these into # a Hash, which can't be split into ordering tokens). return nil unless self.class._safe_query_value?(order_string) return nil unless order_string.present? ordering = {}.with_indifferent_access references = [] order_string = order_string.join(",") if order_string.is_a?(Array) order_string.split(",").map(&:strip).each do |field| if field[0] == "-" column = field[1..-1] direction = :desc else column = field direction = :asc end # A plain, directly-allowlisted field. if column.in?(fields) ordering[column] = direction next end # A polymorphic association's `<name>.id`/`<name>.type` maps to a backing column on the base # table, so it orders directly with no JOIN (unlike other sub-fields). if real_column = poly_columns[column] ordering[real_column] = direction next end # A dotted `association.sub_field` token. The root must be an allowlisted association field, # and the sub-field must be one of that association's allowlisted fields. Otherwise a client # could order by (and infer, via an ordering oracle) a column that is never serialized. root, sub = column.split(".", 2) next unless sub && root.in?(fields) cfg = @controller.class.field_configuration[root] next unless cfg && sub.in?(cfg[:fields] || []) ordering[column] = direction references << root.to_sym end return nil if ordering.empty? [ ordering, references ] end |
#filter_data(data) ⇒ Object
Order data according to the request query parameters.
68 69 70 71 72 73 74 75 76 77 |
# File 'lib/rest_framework/filters/ordering_filter.rb', line 68 def filter_data(data) ordering, references = self._get_ordering return data unless ordering # Join any referenced associations so dotted ordering keys resolve instead of raising. data = data.includes(*references).references(*references) if references.present? reorder = !@controller.class.ordering_no_reorder data.send(reorder ? :reorder : :order, ordering) end |