rest_framework 0.9.15 → 0.10.0

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: 734af1c9a436fd842c36503794ef16b94e4b0d3f7ad91d011bcd12d06e4b1e21
4
- data.tar.gz: d4c0140985a5405750cdd092c4a70b092be69b3523a3c088d2268711c38e5ad1
3
+ metadata.gz: 8a916afbf32cf43553b8aa952024011639f311ab80db53685163e607e48e1ad0
4
+ data.tar.gz: 1cc8aa7aed712a63b1ef9586c37b64a87de62fe5dfdcf659e982a1b77c20fd89
5
5
  SHA512:
6
- metadata.gz: 4fc442c77a0c8543913ceacd7a7116f9e044ee1d9b0e3e08a5c58ddb6d00ee12b7f719c83e7aed233070075bb031aa8a90cabc7337bd57e28883aca4221d5ea6
7
- data.tar.gz: 2f60ffddea13e956a3a0a0ec909d2de533cc0c5b350af75467f7e006b5133c982192cbcc28da7cb566803458c76917ae702f4838c3f0096722a94f5309babb7a
6
+ metadata.gz: bef1f7c3c52c7a42e8c307ccaf37e4e25f4e663359e26be433f20fd644fca0e59cd3b56613f965b084662046577576728981a320d1d5a5a6517d98556008fc99
7
+ data.tar.gz: '080f96e20b330a391b896db89a192e415328aa320f8d669260d8d282c0eee709022afa7fa5dd484449eb5bba85544f8974d24764a5e5b45821803d1ccd3c23f0'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.15
1
+ 0.10.0
@@ -3,11 +3,10 @@
3
3
  <head>
4
4
  <title><%= @title %></title>
5
5
 
6
- <%# These dynamic tags cannot be cached, so include directly instead of in `head` partial. %>
7
6
  <%= csrf_meta_tags %>
8
7
  <%= csp_meta_tag rescue nil %>
9
8
 
10
- <%= render partial: "rest_framework/head", cached: true %>
9
+ <%= render partial: "rest_framework/head" %>
11
10
 
12
11
  <%= yield :head %>
13
12
  </head>
@@ -296,8 +296,9 @@
296
296
  document.write(content)
297
297
  document.close()
298
298
 
299
- // Trigger `DOMContentLoaded` manually so our custom JavaScript works.
300
- document.dispatchEvent(new Event("DOMContentLoaded", {bubbles: true, cancelable: true}))
299
+ // It seems that `DOMContentLoaded` is already triggered on `document.close()`.
300
+ // // Trigger `DOMContentLoaded` manually so our custom JavaScript works.
301
+ // // document.dispatchEvent(new Event("DOMContentLoaded", {bubbles: true, cancelable: true}))
301
302
  }
302
303
 
303
304
  // Refresh the window as a `GET` request.
@@ -3,7 +3,7 @@
3
3
  <%= render partial: "rest_framework/heading/actions" if @route_groups.present? %>
4
4
  <h1 style="margin: 0"><%= @heading_title || @title %></h1>
5
5
  <% if @description.present? %>
6
- <br><br><p style="display: inline-block; margin-bottom: 0"><%= @description %></p>
6
+ <p style="display: inline-block; margin-bottom: 0; margin-top: 1em"><%= @description %></p>
7
7
  <% end %>
8
8
  </div>
9
9
  </div>
@@ -26,14 +26,14 @@
26
26
  %>
27
27
  <div class="mb-2">
28
28
  <% if metadata[:kind] == "rich_text" %>
29
- <label class="form-label w-100"><%= controller.class.get_label(f) %></label>
29
+ <label class="form-label w-100"><%= controller.class.label_for(f) %></label>
30
30
  <%= form.rich_text_area f %>
31
31
  <% elsif metadata[:kind] == "attachment" %>
32
- <label class="form-label w-100"><%= controller.class.get_label(f) %>
32
+ <label class="form-label w-100"><%= controller.class.label_for(f) %>
33
33
  <%= form.file_field f, multiple: metadata.dig(:attachment, :macro) == :has_many_attached %>
34
34
  </label>
35
35
  <% else %>
36
- <label class="form-label w-100"><%= controller.class.get_label(f) %>
36
+ <label class="form-label w-100"><%= controller.class.label_for(f) %>
37
37
  <%= form.text_field f, class: "form-control form-control-sm" %>
38
38
  </label>
39
39
  <% end %>
@@ -40,7 +40,7 @@
40
40
  local: true,
41
41
  }.compact) do |form| %>
42
42
  <% attachment_reflections.each do |field, ref| %>
43
- <label class="form-label w-100"><%= controller.class.get_label(field) %>
43
+ <label class="form-label w-100"><%= controller.class.label_for(field) %>
44
44
  <%= form.file_field field, multiple: ref.macro == :has_many_attached %>
45
45
  </label>
46
46
  <% end %>
@@ -3,7 +3,7 @@ class RESTFramework::Filters::BaseFilter
3
3
  @controller = controller
4
4
  end
5
5
 
6
- def get_filtered_data(data)
6
+ def filter_data(data)
7
7
  raise NotImplementedError
8
8
  end
9
9
  end
@@ -1,5 +1,5 @@
1
1
  # A filter backend which handles ordering of the recordset.
2
- class RESTFramework::Filters::ModelOrderingFilter < RESTFramework::Filters::BaseFilter
2
+ class RESTFramework::Filters::OrderingFilter < RESTFramework::Filters::BaseFilter
3
3
  # Get a list of ordering fields for the current action.
4
4
  def _get_fields
5
5
  return @controller.ordering_fields&.map(&:to_s) || @controller.get_fields
@@ -38,7 +38,7 @@ class RESTFramework::Filters::ModelOrderingFilter < RESTFramework::Filters::Base
38
38
  end
39
39
 
40
40
  # Order data according to the request query parameters.
41
- def get_filtered_data(data)
41
+ def filter_data(data)
42
42
  ordering = self._get_ordering
43
43
  reorder = !@controller.ordering_no_reorder
44
44
 
@@ -51,4 +51,7 @@ class RESTFramework::Filters::ModelOrderingFilter < RESTFramework::Filters::Base
51
51
  end
52
52
 
53
53
  # Alias for convenience.
54
- RESTFramework::ModelOrderingFilter = RESTFramework::Filters::ModelOrderingFilter
54
+ RESTFramework::OrderingFilter = RESTFramework::Filters::OrderingFilter
55
+
56
+ # TODO: Compatibility; remove in 1.0.
57
+ RESTFramework::ModelOrderingFilter = RESTFramework::Filters::OrderingFilter
@@ -1,14 +1,14 @@
1
1
  # A simple filtering backend that supports filtering a recordset based on query parameters.
2
- class RESTFramework::Filters::ModelQueryFilter < RESTFramework::Filters::BaseFilter
2
+ class RESTFramework::Filters::QueryFilter < RESTFramework::Filters::BaseFilter
3
3
  NIL_VALUES = ["nil", "null"].freeze
4
4
 
5
- # Get a list of filterset fields for the current action.
5
+ # Get a list of filter fields for the current action.
6
6
  def _get_fields
7
7
  # Always return a list of strings; `@controller.get_fields` already does this.
8
- return @controller.class.filterset_fields&.map(&:to_s) || @controller.get_fields
8
+ return @controller.class.filter_fields&.map(&:to_s) || @controller.get_fields
9
9
  end
10
10
 
11
- # Filter params for keys allowed by the current action's filterset_fields/fields config.
11
+ # Filter params for keys allowed by the current action's filter_fields/fields config.
12
12
  def _get_filter_params
13
13
  fields = self._get_fields
14
14
  includes = []
@@ -22,7 +22,7 @@ class RESTFramework::Filters::ModelQueryFilter < RESTFramework::Filters::BaseFil
22
22
  field, sub_field = match[1..2]
23
23
  next false unless field.in?(fields)
24
24
 
25
- sub_fields = @controller.class.get_field_config(field)[:sub_fields] || []
25
+ sub_fields = @controller.class.field_config_for(field)[:sub_fields] || []
26
26
  if sub_field.in?(sub_fields)
27
27
  includes << field.to_sym
28
28
  next true
@@ -49,7 +49,7 @@ class RESTFramework::Filters::ModelQueryFilter < RESTFramework::Filters::BaseFil
49
49
  end
50
50
 
51
51
  # Filter data according to the request query parameters.
52
- def get_filtered_data(data)
52
+ def filter_data(data)
53
53
  filter_params, includes = self._get_filter_params
54
54
 
55
55
  if filter_params.any?
@@ -65,4 +65,7 @@ class RESTFramework::Filters::ModelQueryFilter < RESTFramework::Filters::BaseFil
65
65
  end
66
66
 
67
67
  # Alias for convenience.
68
- RESTFramework::ModelQueryFilter = RESTFramework::Filters::ModelQueryFilter
68
+ RESTFramework::QueryFilter = RESTFramework::Filters::QueryFilter
69
+
70
+ # TODO: Compatibility; remove in 1.0.
71
+ RESTFramework::ModelQueryFilter = RESTFramework::Filters::QueryFilter
@@ -1,7 +1,7 @@
1
1
  # Adapter for the `ransack` gem.
2
2
  class RESTFramework::Filters::RansackFilter < RESTFramework::Filters::BaseFilter
3
3
  # Filter data according to the request query parameters.
4
- def get_filtered_data(data)
4
+ def filter_data(data)
5
5
  q = @controller.request.query_parameters[@controller.ransack_query_param]
6
6
 
7
7
  if q.present?
@@ -1,5 +1,4 @@
1
- # Multi-field text searching on models.
2
- class RESTFramework::Filters::ModelSearchFilter < RESTFramework::Filters::BaseFilter
1
+ class RESTFramework::Filters::SearchFilter < RESTFramework::Filters::BaseFilter
3
2
  # Get a list of search fields for the current action.
4
3
  def _get_fields
5
4
  if search_fields = @controller.search_fields
@@ -13,7 +12,7 @@ class RESTFramework::Filters::ModelSearchFilter < RESTFramework::Filters::BaseFi
13
12
  end
14
13
 
15
14
  # Filter data according to the request query parameters.
16
- def get_filtered_data(data)
15
+ def filter_data(data)
17
16
  search = @controller.request.query_parameters[@controller.search_query_param]
18
17
 
19
18
  if search.present?
@@ -41,4 +40,7 @@ class RESTFramework::Filters::ModelSearchFilter < RESTFramework::Filters::BaseFi
41
40
  end
42
41
 
43
42
  # Alias for convenience.
44
- RESTFramework::ModelSearchFilter = RESTFramework::Filters::ModelSearchFilter
43
+ RESTFramework::SearchFilter = RESTFramework::Filters::SearchFilter
44
+
45
+ # TODO: Compatibility; remove in 1.0.
46
+ RESTFramework::ModelSearchFilter = RESTFramework::Filters::SearchFilter
@@ -3,7 +3,7 @@ end
3
3
 
4
4
  require_relative "filters/base_filter"
5
5
 
6
- require_relative "filters/model_ordering_filter"
7
- require_relative "filters/model_query_filter"
8
- require_relative "filters/model_search_filter"
6
+ require_relative "filters/ordering_filter"
7
+ require_relative "filters/query_filter"
9
8
  require_relative "filters/ransack_filter"
9
+ require_relative "filters/search_filter"
@@ -1,6 +1,6 @@
1
1
  # This module provides the common functionality for any controller mixins, a `root` action, and
2
- # the ability to route arbitrary actions with `extra_actions`. This is also where `api_response`
3
- # is defined.
2
+ # the ability to route arbitrary actions with `extra_actions`. This is also where `render_api` is
3
+ # implemented.
4
4
  module RESTFramework::Mixins::BaseControllerMixin
5
5
  RRF_BASE_CONFIG = {
6
6
  extra_actions: nil,
@@ -11,9 +11,6 @@ module RESTFramework::Mixins::BaseControllerMixin
11
11
  title: nil,
12
12
  description: nil,
13
13
  inflect_acronyms: ["ID", "IDs", "REST", "API", "APIs"].freeze,
14
- }
15
- RRF_BASE_INSTANCE_CONFIG = {
16
- filter_backends: nil,
17
14
 
18
15
  # Options related to serialization.
19
16
  rescue_unknown_format_with: :json,
@@ -21,6 +18,11 @@ module RESTFramework::Mixins::BaseControllerMixin
21
18
  serialize_to_json: true,
22
19
  serialize_to_xml: true,
23
20
 
21
+ # Custom integrations (reduces serializer performance due to method calls).
22
+ enable_action_text: false,
23
+ enable_active_storage: false,
24
+ }
25
+ RRF_BASE_INSTANCE_CONFIG = {
24
26
  # Options related to pagination.
25
27
  paginator_class: nil,
26
28
  page_size: 20,
@@ -35,12 +37,12 @@ module RESTFramework::Mixins::BaseControllerMixin
35
37
 
36
38
  # Default action for API root.
37
39
  def root
38
- api_response({message: "This is the API root."})
40
+ render_api({message: "This is the API root."})
39
41
  end
40
42
 
41
43
  module ClassMethods
42
- # Get the title of this controller. By default, this is the name of the controller class,
43
- # titleized and with any custom inflection acronyms applied.
44
+ # By default, this is the name of the controller class, titleized and with any custom inflection
45
+ # acronyms applied.
44
46
  def get_title
45
47
  return self.title || RESTFramework::Utils.inflect(
46
48
  self.name.demodulize.chomp("Controller").titleize(keep_id_suffix: true),
@@ -49,7 +51,7 @@ module RESTFramework::Mixins::BaseControllerMixin
49
51
  end
50
52
 
51
53
  # Get a label from a field/column name, titleized and inflected.
52
- def get_label(s)
54
+ def label_for(s)
53
55
  return RESTFramework::Utils.inflect(
54
56
  s.to_s.titleize(keep_id_suffix: true),
55
57
  self.inflect_acronyms,
@@ -57,7 +59,7 @@ module RESTFramework::Mixins::BaseControllerMixin
57
59
  end
58
60
 
59
61
  # Collect actions (including extra actions) metadata for this controller.
60
- def get_actions_metadata
62
+ def actions_metadata
61
63
  actions = {}
62
64
 
63
65
  # Start with builtin actions.
@@ -67,7 +69,7 @@ module RESTFramework::Mixins::BaseControllerMixin
67
69
  next unless self.method_defined?(action)
68
70
 
69
71
  actions[action] = {
70
- path: "", methods: methods, type: :builtin, metadata: {label: self.get_label(action)}
72
+ path: "", methods: methods, type: :builtin, metadata: {label: self.label_for(action)}
71
73
  }
72
74
  end
73
75
 
@@ -76,7 +78,7 @@ module RESTFramework::Mixins::BaseControllerMixin
76
78
  next unless self.method_defined?(action)
77
79
 
78
80
  actions[action] = {
79
- path: "", methods: methods, type: :builtin, metadata: {label: self.get_label(action)}
81
+ path: "", methods: methods, type: :builtin, metadata: {label: self.label_for(action)}
80
82
  }
81
83
  end
82
84
 
@@ -89,7 +91,7 @@ module RESTFramework::Mixins::BaseControllerMixin
89
91
  end
90
92
 
91
93
  # Collect member actions (including extra member actions) metadata for this controller.
92
- def get_member_actions_metadata
94
+ def member_actions_metadata
93
95
  actions = {}
94
96
 
95
97
  # Start with builtin actions.
@@ -97,7 +99,7 @@ module RESTFramework::Mixins::BaseControllerMixin
97
99
  next unless self.method_defined?(action)
98
100
 
99
101
  actions[action] = {
100
- path: "", methods: methods, type: :builtin, metadata: {label: self.get_label(action)}
102
+ path: "", methods: methods, type: :builtin, metadata: {label: self.label_for(action)}
101
103
  }
102
104
  end
103
105
 
@@ -109,8 +111,7 @@ module RESTFramework::Mixins::BaseControllerMixin
109
111
  return actions
110
112
  end
111
113
 
112
- # Get a hash of metadata to be rendered in the `OPTIONS` response. Cache the result.
113
- def get_options_metadata
114
+ def options_metadata
114
115
  return {
115
116
  title: self.get_title,
116
117
  description: self.description,
@@ -119,8 +120,8 @@ module RESTFramework::Mixins::BaseControllerMixin
119
120
  self.serialize_to_json ? "application/json" : nil,
120
121
  self.serialize_to_xml ? "application/xml" : nil,
121
122
  ].compact,
122
- actions: self.get_actions_metadata,
123
- member_actions: self.get_member_actions_metadata,
123
+ actions: self.actions_metadata,
124
+ member_actions: self.member_actions_metadata,
124
125
  }.compact
125
126
  end
126
127
 
@@ -203,47 +204,24 @@ module RESTFramework::Mixins::BaseControllerMixin
203
204
  end
204
205
  end
205
206
 
206
- # Get the configured serializer class.
207
- def get_serializer_class
208
- return nil unless serializer_class = self.serializer_class
209
-
210
- # Support dynamically resolving serializer given a symbol or string.
211
- serializer_class = serializer_class.to_s if serializer_class.is_a?(Symbol)
212
- if serializer_class.is_a?(String)
213
- serializer_class = self.class.const_get(serializer_class)
214
- end
215
-
216
- # Wrap it with an adapter if it's an active_model_serializer.
217
- if defined?(ActiveModel::Serializer) && (serializer_class < ActiveModel::Serializer)
218
- serializer_class = RESTFramework::ActiveModelSerializerAdapterFactory.for(serializer_class)
207
+ def serializer_class
208
+ # TODO: Compatibility; remove in 1.0.
209
+ if klass = self.try(:get_serializer_class)
210
+ return klass
219
211
  end
220
212
 
221
- return serializer_class
213
+ return self.class.serializer_class
222
214
  end
223
215
 
224
216
  # Serialize the given data using the `serializer_class`.
225
217
  def serialize(data, **kwargs)
226
- return self.get_serializer_class.new(data, controller: self, **kwargs).serialize
218
+ return RESTFramework::Utils.wrap_ams(self.serializer_class).new(
219
+ data, controller: self, **kwargs
220
+ ).serialize
227
221
  end
228
222
 
229
- # Get filtering backends, defaulting to no backends.
230
- def get_filter_backends
231
- return self.filter_backends || []
232
- end
233
-
234
- # Filter an arbitrary data set over all configured filter backends.
235
- def get_filtered_data(data)
236
- # Apply each filter sequentially.
237
- self.get_filter_backends.each do |filter_class|
238
- filter = filter_class.new(controller: self)
239
- data = filter.get_filtered_data(data)
240
- end
241
-
242
- return data
243
- end
244
-
245
- def get_options_metadata
246
- return self.class.get_options_metadata
223
+ def options_metadata
224
+ return self.class.options_metadata
247
225
  end
248
226
 
249
227
  def rrf_error_handler(e)
@@ -295,25 +273,25 @@ module RESTFramework::Mixins::BaseControllerMixin
295
273
  begin
296
274
  respond_to do |format|
297
275
  if payload == ""
298
- format.json { head(kwargs[:status] || :no_content) } if self.serialize_to_json
299
- format.xml { head(kwargs[:status] || :no_content) } if self.serialize_to_xml
276
+ format.json { head(kwargs[:status] || :no_content) } if self.class.serialize_to_json
277
+ format.xml { head(kwargs[:status] || :no_content) } if self.class.serialize_to_xml
300
278
  else
301
279
  format.json {
302
280
  render(json: payload, **kwargs.merge(json_kwargs))
303
- } if self.serialize_to_json
281
+ } if self.class.serialize_to_json
304
282
  format.xml {
305
283
  render(xml: payload, **kwargs.merge(xml_kwargs))
306
- } if self.serialize_to_xml
284
+ } if self.class.serialize_to_xml
307
285
  # TODO: possibly support more formats here if supported?
308
286
  end
309
287
  format.html {
310
288
  @payload = payload
311
289
  if payload == ""
312
- @json_payload = "" if self.serialize_to_json
313
- @xml_payload = "" if self.serialize_to_xml
290
+ @json_payload = "" if self.class.serialize_to_json
291
+ @xml_payload = "" if self.class.serialize_to_xml
314
292
  else
315
- @json_payload = payload.to_json if self.serialize_to_json
316
- @xml_payload = payload.to_xml if self.serialize_to_xml
293
+ @json_payload = payload.to_json if self.class.serialize_to_json
294
+ @xml_payload = payload.to_xml if self.class.serialize_to_xml
317
295
  end
318
296
  @title ||= self.class.get_title
319
297
  @description ||= self.class.description
@@ -329,7 +307,7 @@ module RESTFramework::Mixins::BaseControllerMixin
329
307
  }
330
308
  end
331
309
  rescue ActionController::UnknownFormat
332
- if !already_rescued_unknown_format && rescue_format = self.rescue_unknown_format_with
310
+ if !already_rescued_unknown_format && rescue_format = self.class.rescue_unknown_format_with
333
311
  request.format = rescue_format
334
312
  already_rescued_unknown_format = true
335
313
  retry
@@ -339,9 +317,11 @@ module RESTFramework::Mixins::BaseControllerMixin
339
317
  end
340
318
  end
341
319
 
342
- # Provide a generic `OPTIONS` response with metadata such as available actions.
320
+ # TODO: Might make this the default render method in the future.
321
+ alias_method :render_api, :api_response
322
+
343
323
  def options
344
- return api_response(self.get_options_metadata)
324
+ return api_response(self.options_metadata)
345
325
  end
346
326
  end
347
327
 
@@ -6,7 +6,7 @@ module RESTFramework::Mixins::BulkCreateModelMixin
6
6
  # While bulk update/destroy are obvious because they create new router endpoints, bulk create
7
7
  # overloads the existing collection `POST` endpoint, so we add a special key to the options
8
8
  # metadata to indicate bulk create is supported.
9
- def get_options_metadata
9
+ def options_metadata
10
10
  return super.merge({bulk_create: true})
11
11
  end
12
12