Skip to content

Commit

Permalink
Make default label fields and search columns configurable.
Browse files Browse the repository at this point in the history
  • Loading branch information
gregschmit committed Jan 30, 2023
1 parent 34b8844 commit 9cae60a
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 6 deletions.
12 changes: 10 additions & 2 deletions docs/_guide/4_filtering_and_ordering.md
Expand Up @@ -12,15 +12,15 @@ 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`.

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`.
Expand All @@ -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`).
12 changes: 11 additions & 1 deletion lib/rest_framework.rb
Expand Up @@ -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
Expand All @@ -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

Expand Down
6 changes: 3 additions & 3 deletions 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.
Expand Down Expand Up @@ -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

Expand Down

0 comments on commit 9cae60a

Please sign in to comment.