Module: RESTFramework::BaseModelControllerMixin

Includes:
BaseControllerMixin
Included in:
ModelControllerMixin, ReadOnlyModelControllerMixin
Defined in:
lib/rest_framework/controller_mixins/models.rb

Overview

This module provides the core functionality for controllers based on models.

Class Method Summary collapse

Instance Method Summary collapse

Methods included from BaseControllerMixin

#api_response, #get_filtered_data, #record_invalid, #record_not_destroyed, #record_not_found, #record_not_saved, #root

Class Method Details

.included(base) ⇒ Object



8
9
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
# File 'lib/rest_framework/controller_mixins/models.rb', line 8

def self.included(base)
  if base.is_a?(Class)
    RESTFramework::BaseControllerMixin.included(base)

    # Add class attributes (with defaults) unless they already exist.
    {
      # Core attributes related to models.
      model: nil,
      recordset: nil,

      # Attributes for configuring record fields.
      fields: nil,
      action_fields: nil,

      # Attributes for finding records.
      find_by_fields: nil,
      find_by_query_param: "find_by",

      # Attributes for create/update parameters.
      allowed_parameters: nil,
      allowed_action_parameters: nil,

      # Attributes for the default native serializer.
      native_serializer_config: nil,
      native_serializer_singular_config: nil,
      native_serializer_plural_config: nil,
      native_serializer_only_query_param: "only",
      native_serializer_except_query_param: "except",

      # Attributes for default model filtering (and ordering).
      filterset_fields: nil,
      ordering_fields: nil,
      ordering_query_param: "ordering",
      ordering_no_reorder: false,
      search_fields: nil,
      search_query_param: "search",
      search_ilike: false,

      # Other misc attributes.
      create_from_recordset: true,  # Option for `recordset.create` vs `Model.create` behavior.
      filter_recordset_before_find: true,  # Option to control if filtering is done before find.
    }.each do |a, default|
      next if base.respond_to?(a)

      base.class_attribute(a)

      # Set default manually so we can still support Rails 4. Maybe later we can use the default
      # parameter on `class_attribute`.
      base.send(:"#{a}=", default)
    end
  end
end

Instance Method Details

#_get_specific_action_config(action_config_key, generic_config_key) ⇒ Object



61
62
63
64
65
66
67
68
69
# File 'lib/rest_framework/controller_mixins/models.rb', line 61

def _get_specific_action_config(action_config_key, generic_config_key)
  action_config = self.class.send(action_config_key) || {}
  action = self.action_name&.to_sym

  # Index action should use :list serializer if :index is not provided.
  action = :list if action == :index && !action_config.key?(:index)

  return (action_config[action] if action) || self.class.send(generic_config_key)
end

#get_allowed_parametersObject

Get a list of parameters allowed for the current action.



101
102
103
# File 'lib/rest_framework/controller_mixins/models.rb', line 101

def get_allowed_parameters
  return _get_specific_action_config(:allowed_action_parameters, :allowed_parameters)&.map(&:to_s)
end

#get_body_paramsObject Also known as: get_create_params, get_update_params

Filter the request body for keys in current action’s allowed_parameters/fields config.



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/rest_framework/controller_mixins/models.rb', line 118

def get_body_params
  return @_get_body_params ||= begin
    fields = self.get_allowed_parameters || self.get_fields

    # Filter the request body.
    body_params = request.request_parameters.select { |p| fields.include?(p) }

    # Add query params in place of missing body params, if configured.
    if self.class.accept_generic_params_as_body_params
      (fields - body_params.keys).each do |k|
        if (value = params[k])
          body_params[k] = value
        end
      end
    end

    # Filter primary key if configured.
    if self.class.filter_pk_from_request_body
      body_params.delete(self.get_model&.primary_key)
    end

    # Filter fields in exclude_body_fields.
    (self.class.exclude_body_fields || []).each { |f| body_params.delete(f.to_s) }

    body_params
  end
end

#get_fieldsObject

Get a list of fields for the current action.



72
73
74
75
76
77
78
# File 'lib/rest_framework/controller_mixins/models.rb', line 72

def get_fields
  return (
    _get_specific_action_config(:action_fields, :fields)&.map(&:to_s) ||
    self.get_model&.column_names ||
    []
  )
end

#get_filter_backendsObject

Helper to get filtering backends, defaulting to using ‘ModelFilter` and `ModelOrderingFilter`.



111
112
113
114
115
# File 'lib/rest_framework/controller_mixins/models.rb', line 111

def get_filter_backends
  return self.class.filter_backends || [
    RESTFramework::ModelFilter, RESTFramework::ModelOrderingFilter
  ]
end

#get_filterset_fieldsObject

Get a list of find_by fields for the current action.



86
87
88
# File 'lib/rest_framework/controller_mixins/models.rb', line 86

def get_filterset_fields
  return self.class.filterset_fields&.map(&:to_s) || self.get_fields
end

#get_find_by_fieldsObject

Get a list of find_by fields for the current action.



81
82
83
# File 'lib/rest_framework/controller_mixins/models.rb', line 81

def get_find_by_fields
  return self.class.find_by_fields&.map(&:to_s) || self.get_fields
end

#get_model(from_get_recordset: false) ⇒ Object

Get the model for this controller.



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/rest_framework/controller_mixins/models.rb', line 149

def get_model(from_get_recordset: false)
  return @model if instance_variable_defined?(:@model) && @model
  return (@model = self.class.model) if self.class.model

  # Delegate to the recordset's model, if it's defined.
  unless from_get_recordset  # prevent infinite recursion
    if (recordset = self.get_recordset)
      return @model = recordset.klass
    end
  end

  # Try to determine model from controller name.
  begin
    return @model = self.class.name.demodulize.match(/(.*)Controller/)[1].singularize.constantize
  rescue NameError
  end

  return nil
end

#get_ordering_fieldsObject

Get a list of ordering fields for the current action.



91
92
93
# File 'lib/rest_framework/controller_mixins/models.rb', line 91

def get_ordering_fields
  return self.class.ordering_fields&.map(&:to_s) || self.get_fields
end

#get_recordObject

Get a single record by primary key or another column, if allowed.



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/rest_framework/controller_mixins/models.rb', line 183

def get_record
  recordset = self.get_recordset
  find_by_fields = self.get_find_by_fields
  find_by_key = self.get_model.primary_key

  # Find by another column if it's permitted.
  if find_by_query_param && params[find_by_query_param].in?(find_by_fields)
    find_by_key = params[find_by_query_param]
  end

  # Filter recordset, if configured.
  if self.filter_recordset_before_find
    recordset = self.get_filtered_data(recordset)
  end

  # Return the record. Route key is always :id by Rails convention.
  return recordset.find_by!(find_by_key => params[:id])
end

#get_recordsetObject

Get the set of records this controller has access to.



170
171
172
173
174
175
176
177
178
179
180
# File 'lib/rest_framework/controller_mixins/models.rb', line 170

def get_recordset
  return @recordset if instance_variable_defined?(:@recordset) && @recordset
  return (@recordset = self.class.recordset) if self.class.recordset

  # If there is a model, return that model's default scope (all records by default).
  if (model = self.get_model(from_get_recordset: true))
    return @recordset = model.all
  end

  return nil
end

#get_search_fieldsObject

Get a list of search fields for the current action.



96
97
98
# File 'lib/rest_framework/controller_mixins/models.rb', line 96

def get_search_fields
  return self.class.search_fields&.map(&:to_s) || self.get_fields
end

#get_serializer_classObject

Helper to get the configured serializer class, or ‘NativeSerializer` as a default.



106
107
108
# File 'lib/rest_framework/controller_mixins/models.rb', line 106

def get_serializer_class
  return super || RESTFramework::NativeSerializer
end