From 9cae60ab3044714ad292018e9a63a26a2c410440 Mon Sep 17 00:00:00 2001 From: "Gregory N. Schmit" Date: Mon, 30 Jan 2023 16:04:19 -0600 Subject: [PATCH] Make default label fields and search columns configurable. --- docs/_guide/4_filtering_and_ordering.md | 12 ++++++++++-- lib/rest_framework.rb | 12 +++++++++++- lib/rest_framework/utils.rb | 6 +++--- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/docs/_guide/4_filtering_and_ordering.md b/docs/_guide/4_filtering_and_ordering.md index 5d0d89d..2e2168a 100644 --- a/docs/_guide/4_filtering_and_ordering.md +++ b/docs/_guide/4_filtering_and_ordering.md @@ -12,7 +12,7 @@ accomplished through what we call filters. To control the filter backends that a you can either adjust the `filter_backends` controller attribute or you can override the `get_filter_backends()` method. -## ModelFilter +## `ModelFilter` This filter provides basic user-controllable filtering of the recordset using query params. For example, a request to `/api/movies?cool=true` could return movies where `cool` is `true`. @@ -20,7 +20,7 @@ example, a request to `/api/movies?cool=true` could return movies where `cool` i If you include `ModelControllerMixin` into your controller, `ModelFilter` is included in the filter backends by default. -## ModelOrderingFilter +## `ModelOrderingFilter` This filter provides basic user-controllable ordering of the recordset using query params. For example, a request to `/api/movies?ordering=name` could order the movies by `name` rather than `id`. @@ -31,3 +31,11 @@ If you include `ModelControllerMixin` into your controller, `ModelOrderingFilter filter backends by default. You can use `ordering_fields` to controller which fields are allowed to be ordered by. To adjust the parameter that the user passes, adjust `ordering_query_param`; the default is `"ordering"`. + +## `ModelSearchFilter` + +This filter provides basic user-controllable searching of the recordset using the `search` query +parameter (adjustable with the `search_query_param`). For example, a request to +`/api/movies?search=Star` could return movies where `name` contains the string `Star`. The search is +performed against the `search_fields` attribute, but if that is not set, then the search is +performed against a configurable default set of fields (`search_columns`). diff --git a/lib/rest_framework.rb b/lib/rest_framework.rb index 7a8294a..f8c8a71 100644 --- a/lib/rest_framework.rb +++ b/lib/rest_framework.rb @@ -26,6 +26,8 @@ class Config ActiveStorage::Attachment ActiveStorage::Blob ).freeze + DEFAULT_LABEL_FIELDS = %w(name label login title email username url).freeze + DEFAULT_SEARCH_COLUMNS = DEFAULT_LABEL_FIELDS + %w(description note).freeze # Do not run `rrf_finalize` on controllers automatically using a `TracePoint` hook. This is a # performance option and must be global because we have to determine this before any @@ -50,12 +52,20 @@ class Config # Option to disable `rescue_from` on the controller mixins. attr_accessor :disable_rescue_from - # Options to exclude certain classes from being added by default as association fields. + # Option to exclude certain classes from being added by default as association fields. attr_accessor :exclude_association_classes + # Option for the default label fields to use when generating labels for `has_many` associations. + attr_accessor :label_fields + + # Option for the default search columns to use when generating search filters. + attr_accessor :search_columns + def initialize self.show_backtrace = Rails.env.development? self.exclude_association_classes = DEFAULT_EXCLUDE_ASSOCIATION_CLASSES + self.label_fields = DEFAULT_LABEL_FIELDS + self.search_columns = DEFAULT_SEARCH_COLUMNS end end diff --git a/lib/rest_framework/utils.rb b/lib/rest_framework/utils.rb index cf125d6..3ac071d 100644 --- a/lib/rest_framework/utils.rb +++ b/lib/rest_framework/utils.rb @@ -1,6 +1,5 @@ module RESTFramework::Utils HTTP_METHOD_ORDERING = %w(GET POST PUT PATCH DELETE OPTIONS HEAD) - LABEL_FIELDS = %w(name label login title email username url) # Convert `extra_actions` hash to a consistent format: `{path:, methods:, kwargs:}`, and # additional metadata fields. @@ -186,14 +185,15 @@ def self.fields_for(model, exclude_associations: nil) def self.sub_fields_for(ref) if !ref.polymorphic? && model = ref.klass sub_fields = [model.primary_key].flatten.compact + label_fields = RESTFramework.config.label_fields # Preferrably find a database column to use as label. - if match = LABEL_FIELDS.find { |f| f.in?(model.column_names) } + if match = label_fields.find { |f| f.in?(model.column_names) } return sub_fields + [match] end # Otherwise, find a method. - if match = LABEL_FIELDS.find { |f| model.method_defined?(f) } + if match = label_fields.find { |f| model.method_defined?(f) } return sub_fields + [match] end