rest_framework 0.9.9 → 0.9.10

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: 4b816fbe24e240ce66a74b2a3c18fd0a75a449c878c9a0126e4c14ddbaafe5b8
4
- data.tar.gz: 383836204fd789afd4270794e0d7da57e05b8b8e8f537dd19c7fa2bf6ff1e2eb
3
+ metadata.gz: 2db255f618d449ef621f1337d182993c21b5d8d87e5e8c960c8b42093248c91d
4
+ data.tar.gz: 4612f2e11733ae69e418cd2877b8150e2a1dbd4fb0cd34ed29727dcec007f305
5
5
  SHA512:
6
- metadata.gz: 0a845ce1b30eab8ad874e432268092e5e9117200a320d9446a3e333a88d202257987767fd6b9bad2b7b0768c52e564e1a0beede15408027c7c48c8b91beffcd4
7
- data.tar.gz: a1ae6ccfd603c7759d5db717249790a7b124bc06b39ff3f88eba16527874ec8788e4fdcb149c4e96ca0a6a8dae1ea3361519acfb830e1dfda6bc5ea2b521177b
6
+ metadata.gz: 04457aa989c261900e8e1e55829dbb3cc3aed3afda800433944497996a330a92fdff403351be8e4b83b7b44fea658ecd57a3ab20b4b9e41587398a52b8203680
7
+ data.tar.gz: e67d99fd29629b7bf31e37f3f27edc8e7d5d222172e6b91e5d2340eec0d891b340029097dc798411410d9c5ecbdffe316521c0dd47e8810c6fe897b0ff59624b
data/README.md CHANGED
@@ -7,12 +7,10 @@
7
7
 
8
8
  A framework for DRY RESTful APIs in Ruby on Rails.
9
9
 
10
- **The Problem**: Building controllers for APIs usually involves writing a lot of redundant CRUD
11
- logic, and routing them can be obnoxious. Building and maintaining features like ordering,
12
- filtering, and pagination can be tedious.
10
+ **The Problem**: Building controllers for APIs usually involves writing a lot of redundant CRUD logic, and routing them can be obnoxious.
11
+ Building and maintaining features like ordering, filtering, and pagination can be tedious.
13
12
 
14
- **The Solution**: This framework implements browsable API responses, CRUD actions for your models,
15
- and features like ordering/filtering/pagination, so you can focus on building awesome APIs.
13
+ **The Solution**: This framework implements browsable API responses, CRUD actions for your models, and features like ordering/filtering/pagination, so you can focus on building awesome APIs.
16
14
 
17
15
  Website/Guide: [rails-rest-framework.com](https://rails-rest-framework.com)
18
16
 
@@ -40,8 +38,7 @@ bundle install
40
38
 
41
39
  This section provides some simple examples to quickly get you started using the framework.
42
40
 
43
- For the purpose of this example, you'll want to add an `api_controller.rb` to your controllers, as
44
- well as a directory for the resources:
41
+ For the purpose of this example, you'll want to add an `api_controller.rb` to your controllers, as well as a directory for the resources:
45
42
 
46
43
  ```text
47
44
  controllers/
@@ -54,8 +51,7 @@ controllers/
54
51
 
55
52
  ### Controller Mixins
56
53
 
57
- The root `ApiController` can include any common behavior you want to share across all your API
58
- controllers:
54
+ The root `ApiController` can include any common behavior you want to share across all your API controllers:
59
55
 
60
56
  ```ruby
61
57
  class ApiController < ApplicationController
@@ -71,9 +67,8 @@ class ApiController < ApplicationController
71
67
  end
72
68
  ```
73
69
 
74
- A root controller can provide actions that exist on the root of your API. It's best to define a
75
- dedicated root controller, rather than using the `ApiController` for this purpose, so that actions
76
- don't propagate to child controllers:
70
+ A root controller can provide actions that exist on the root of your API.
71
+ It's best to define a dedicated root controller, rather than using the `ApiController` for this purpose, so that actions don't propagate to child controllers:
77
72
 
78
73
  ```ruby
79
74
  class Api::RootController < ApiController
@@ -119,7 +114,8 @@ class Api::MoviesController < ApiController
119
114
  end
120
115
  ```
121
116
 
122
- You can also configure a resource's fields dynamically using `include` and `exclude` keys:
117
+ When `fields` is nil, then it will default to all columns.
118
+ The `fields` attribute can also be a hash to include or exclude fields rather than defining them manually:
123
119
 
124
120
  ```ruby
125
121
  class Api::UsersController < ApiController
@@ -131,10 +127,9 @@ end
131
127
 
132
128
  ### Routing
133
129
 
134
- You can use Rails' `resource`/`resources` routers to route your API, however if you want
135
- `extra_actions` / `extra_member_actions` to be routed automatically, then you can use `rest_route`
136
- for non-resourceful controllers, or `rest_resource` / `rest_resources` resourceful routers. To route
137
- the root, use `rest_root`.
130
+ Use `rest_route` for non-resourceful controllers, or `rest_resource` / `rest_resources` resourceful routers.
131
+ These routers add some features to the Rails builtin `resource`/`resources` routers, such as automatically routing extra actions defined on the controller.
132
+ To route the root, use `rest_root`.
138
133
 
139
134
  ```ruby
140
135
  Rails.application.routes.draw do
@@ -151,8 +146,7 @@ end
151
146
 
152
147
  ## Development/Testing
153
148
 
154
- After you clone the repository, cd'ing into the directory should create a new gemset if you are
155
- using RVM. Then run `bin/setup` to install the appropriate gems and set things up.
149
+ After you clone the repository, cd'ing into the directory should create a new gemset if you are using RVM.
150
+ Then run `bin/setup` to install the appropriate gems and set things up.
156
151
 
157
- The top-level `bin/rails` proxies all Rails commands to the test project, so you can operate it via
158
- the usual commands (e.g., `rails test`, `rails server` and `rails console`).
152
+ The top-level `bin/rails` proxies all Rails commands to the test project, so you can operate it via the usual commands (e.g., `rails test`, `rails server` and `rails console`).
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.9
1
+ 0.9.10
@@ -15,6 +15,7 @@ class RESTFramework::Filters::ModelOrderingFilter < RESTFramework::Filters::Base
15
15
 
16
16
  if order_string.present?
17
17
  ordering = {}.with_indifferent_access
18
+
18
19
  order_string.split(",").each do |field|
19
20
  if field[0] == "-"
20
21
  column = field[1..-1]
@@ -24,10 +25,11 @@ class RESTFramework::Filters::ModelOrderingFilter < RESTFramework::Filters::Base
24
25
  direction = :asc
25
26
  end
26
27
 
27
- next if !column.in?(fields) && column.split(".").first.in?(fields)
28
+ next if !column.in?(fields) && !column.split(".").first.in?(fields)
28
29
 
29
30
  ordering[column] = direction
30
31
  end
32
+
31
33
  return ordering
32
34
  end
33
35
 
@@ -1,5 +1,7 @@
1
1
  # A simple filtering backend that supports filtering a recordset based on query parameters.
2
2
  class RESTFramework::Filters::ModelQueryFilter < RESTFramework::Filters::BaseFilter
3
+ NIL_VALUES = ["nil", "null"].freeze
4
+
3
5
  # Get a list of filterset fields for the current action.
4
6
  def _get_fields
5
7
  # Always return a list of strings; `@controller.get_fields` already does this.
@@ -9,8 +11,9 @@ class RESTFramework::Filters::ModelQueryFilter < RESTFramework::Filters::BaseFil
9
11
  # Filter params for keys allowed by the current action's filterset_fields/fields config.
10
12
  def _get_filter_params
11
13
  fields = self._get_fields
14
+ includes = []
12
15
 
13
- return @controller.request.query_parameters.select { |p, _|
16
+ filter_params = @controller.request.query_parameters.select { |p, _|
14
17
  # Remove any trailing `__in` from the field name.
15
18
  field = p.chomp("__in")
16
19
 
@@ -20,7 +23,12 @@ class RESTFramework::Filters::ModelQueryFilter < RESTFramework::Filters::BaseFil
20
23
  next false unless field.in?(fields)
21
24
 
22
25
  sub_fields = @controller.class.get_field_config(field)[:sub_fields] || []
23
- next sub_field.in?(sub_fields)
26
+ if sub_field.in?(sub_fields)
27
+ includes << field.to_sym
28
+ next true
29
+ end
30
+
31
+ next false
24
32
  end
25
33
 
26
34
  next field.in?(fields)
@@ -28,21 +36,27 @@ class RESTFramework::Filters::ModelQueryFilter < RESTFramework::Filters::BaseFil
28
36
  # Convert fields ending in `__in` to array values.
29
37
  if p.end_with?("__in")
30
38
  p = p.chomp("__in")
31
- v = v.split(",")
39
+ v = v.split(",").map { |v| v.in?(NIL_VALUES) ? nil : v }
32
40
  end
33
41
 
34
42
  # Convert "nil" and "null" to nil.
35
- if v == "nil" || v == "null"
36
- v = nil
37
- end
43
+ v = nil if v.in?(NIL_VALUES)
38
44
 
39
45
  [p, v]
40
46
  }.to_h.symbolize_keys
47
+
48
+ return filter_params, includes
41
49
  end
42
50
 
43
51
  # Filter data according to the request query parameters.
44
52
  def get_filtered_data(data)
45
- if filter_params = self._get_filter_params.presence
53
+ filter_params, includes = self._get_filter_params
54
+
55
+ if filter_params.any?
56
+ if includes.any?
57
+ data = data.includes(*includes)
58
+ end
59
+
46
60
  return data.where(**filter_params)
47
61
  end
48
62
 
@@ -33,17 +33,7 @@ module RESTFramework::Mixins::BaseModelControllerMixin
33
33
  # Options for handling request body parameters.
34
34
  allowed_parameters: nil,
35
35
  filter_pk_from_request_body: true,
36
- exclude_body_fields: %w[
37
- created_at
38
- created_by
39
- created_by_id
40
- updated_at
41
- updated_by
42
- updated_by_id
43
- _method
44
- utf8
45
- authenticity_token
46
- ].freeze,
36
+ exclude_body_fields: RESTFramework.config.exclude_body_fields,
47
37
 
48
38
  # Attributes for the default native serializer.
49
39
  native_serializer_config: nil,
@@ -515,7 +505,7 @@ module RESTFramework::Mixins::BaseModelControllerMixin
515
505
  ActionController::Parameters.new(data).permit(*allowed_params)
516
506
  end
517
507
 
518
- # Filter primary key if configured.
508
+ # Filter primary key, if configured.
519
509
  if self.filter_pk_from_request_body && bulk_mode != :update
520
510
  body_params.delete(pk)
521
511
  end
@@ -527,7 +517,7 @@ module RESTFramework::Mixins::BaseModelControllerMixin
527
517
  #
528
518
  # rubocop:disable Layout/LineLength
529
519
  #
530
- # Good example base64 image:
520
+ # Example base64 image:
531
521
  # data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=
532
522
  #
533
523
  # rubocop:enable Layout/LineLength
@@ -572,7 +562,6 @@ module RESTFramework::Mixins::BaseModelControllerMixin
572
562
  # Cache the result.
573
563
  return @record if @record
574
564
 
575
- recordset = self.get_recordset
576
565
  find_by_key = self.class.get_model.primary_key
577
566
  is_pk = true
578
567
 
@@ -588,16 +577,18 @@ module RESTFramework::Mixins::BaseModelControllerMixin
588
577
  end
589
578
  end
590
579
 
591
- # Filter recordset, if configured.
592
- if self.filter_recordset_before_find
593
- recordset = self.get_records
580
+ # Get the recordset, filtering if configured.
581
+ collection = if self.filter_recordset_before_find
582
+ self.get_records
583
+ else
584
+ self.get_recordset
594
585
  end
595
586
 
596
587
  # Return the record. Route key is always `:id` by Rails convention.
597
588
  if is_pk
598
- return @record = recordset.find(request.path_parameters[:id])
589
+ return @record = collection.find(request.path_parameters[:id])
599
590
  else
600
- return @record = recordset.find_by!(find_by_key => request.path_parameters[:id])
591
+ return @record = collection.find_by!(find_by_key => request.path_parameters[:id])
601
592
  end
602
593
  end
603
594
 
@@ -1,5 +1,5 @@
1
- # Do not use Rails-specific helper methods here (e.g., `blank?`) so the module can run standalone.
2
1
  module RESTFramework
2
+ # Do not use Rails-specific helper methods here (e.g., `blank?`) so the module can run standalone.
3
3
  module Version
4
4
  VERSION_FILEPATH = File.expand_path("../../VERSION", __dir__)
5
5
  UNKNOWN = "0-unknown"
@@ -122,9 +122,19 @@ module RESTFramework
122
122
  # Global configuration should be kept minimal, as controller-level configurations allows multiple
123
123
  # APIs to be defined to behave differently.
124
124
  class Config
125
- DEFAULT_EXCLUDE_ASSOCIATION_CLASSES = [].freeze
126
125
  DEFAULT_LABEL_FIELDS = %w(name label login title email username url).freeze
127
126
  DEFAULT_SEARCH_COLUMNS = DEFAULT_LABEL_FIELDS + %w(description note).freeze
127
+ DEFAULT_EXCLUDE_BODY_FIELDS = %w[
128
+ created_at
129
+ created_by
130
+ created_by_id
131
+ updated_at
132
+ updated_by
133
+ updated_by_id
134
+ _method
135
+ utf8
136
+ authenticity_token
137
+ ].freeze
128
138
 
129
139
  # Do not run `rrf_finalize` on controllers automatically using a `TracePoint` hook. This is a
130
140
  # performance option and must be global because we have to determine this before any
@@ -155,6 +165,9 @@ module RESTFramework
155
165
  # The default search columns to use when generating search filters.
156
166
  attr_accessor :search_columns
157
167
 
168
+ # The default list of fields to exclude from the body of the request.
169
+ attr_accessor :exclude_body_fields
170
+
158
171
  # Option to use vendored assets (requires sprockets or propshaft) rather than linking to
159
172
  # external assets (the default).
160
173
  attr_accessor :use_vendored_assets
@@ -163,6 +176,7 @@ module RESTFramework
163
176
  self.show_backtrace = Rails.env.development?
164
177
  self.label_fields = DEFAULT_LABEL_FIELDS
165
178
  self.search_columns = DEFAULT_SEARCH_COLUMNS
179
+ self.exclude_body_fields = DEFAULT_EXCLUDE_BODY_FIELDS
166
180
  end
167
181
  end
168
182
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rest_framework
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.9
4
+ version: 0.9.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gregory N. Schmit
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-08 00:00:00.000000000 Z
11
+ date: 2023-07-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails