rest_framework 0.9.8 → 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5b06a61592498f8debce6f504b4eee90ceeef6fdff63dbb769bd70c623cd9631
4
- data.tar.gz: ab5b1284a3504104b77cc38278bad01a1dfa30ce7ebcd65323b73e0dd31e58a2
3
+ metadata.gz: 4b816fbe24e240ce66a74b2a3c18fd0a75a449c878c9a0126e4c14ddbaafe5b8
4
+ data.tar.gz: 383836204fd789afd4270794e0d7da57e05b8b8e8f537dd19c7fa2bf6ff1e2eb
5
5
  SHA512:
6
- metadata.gz: ed04505314f252ac1058732a875711090fb07499edac42814bf72e5b15f90f833040e40399df279654727041af30789c8a931e06d83b9fc1c67f46d4f0da850f
7
- data.tar.gz: abd68ae8ab71f2fff8f7a933270a467811143096f7cdde16d21c99ac3faeadc8f958cb0bcdde94c1b57f1d620fc278f8d9b5e3b4e2cec5851fb4616f9c325d41
6
+ metadata.gz: 0a845ce1b30eab8ad874e432268092e5e9117200a320d9446a3e333a88d202257987767fd6b9bad2b7b0768c52e564e1a0beede15408027c7c48c8b91beffcd4
7
+ data.tar.gz: a1ae6ccfd603c7759d5db717249790a7b124bc06b39ff3f88eba16527874ec8788e4fdcb149c4e96ca0a6a8dae1ea3361519acfb830e1dfda6bc5ea2b521177b
data/README.md CHANGED
@@ -27,87 +27,122 @@ YARD Docs: [rubydoc.info/gems/rest_framework](https://rubydoc.info/gems/rest_fra
27
27
  Add this line to your application's Gemfile:
28
28
 
29
29
  ```ruby
30
- gem 'rest_framework'
30
+ gem "rest_framework"
31
31
  ```
32
32
 
33
- And then execute:
33
+ And then run:
34
34
 
35
35
  ```shell
36
- $ bundle install
36
+ bundle install
37
37
  ```
38
38
 
39
- Or install it yourself with:
39
+ ## Quick Usage Tutorial
40
40
 
41
- ```shell
42
- $ gem install rest_framework
43
- ```
41
+ This section provides some simple examples to quickly get you started using the framework.
44
42
 
45
- ## Quick Usage Tutorial
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:
45
+
46
+ ```text
47
+ controllers/
48
+ ├─ api_controller.rb
49
+ └─ api/
50
+ ├─ root_controller.rb
51
+ ├─ movies_controller.rb
52
+ └─ users_controller.rb
53
+ ```
46
54
 
47
55
  ### Controller Mixins
48
56
 
49
- To transform a controller into a RESTful controller, you can either include `BaseControllerMixin`,
50
- `ReadOnlyModelControllerMixin`, or `ModelControllerMixin`. `BaseControllerMixin` provides a `root`
51
- action and a simple interface for routing arbitrary additional actions:
57
+ The root `ApiController` can include any common behavior you want to share across all your API
58
+ controllers:
52
59
 
53
60
  ```ruby
54
61
  class ApiController < ApplicationController
55
62
  include RESTFramework::BaseControllerMixin
63
+
64
+ # Setting up a paginator class here makes more sense than defining it on every child controller.
65
+ self.paginator_class = RESTFramework::PageNumberPaginator
66
+
67
+ # The page_size attribute doesn't exist on the `BaseControllerMixin`, but for child controllers
68
+ # that include the `ModelControllerMixin`, they will inherit this attribute and will not overwrite
69
+ # it.
70
+ class_attribute(:page_size, default: 30)
71
+ end
72
+ ```
73
+
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:
77
+
78
+ ```ruby
79
+ class Api::RootController < ApiController
56
80
  self.extra_actions = {test: :get}
57
81
 
82
+ def root
83
+ return api_response(
84
+ {
85
+ message: "Welcome to the API.",
86
+ how_to_authenticate: <<~END.lines.map(&:strip).join(" "),
87
+ You can use this API with your normal login session. Otherwise, you can insert your API
88
+ key into a Bearer Authorization header, or into the URL parameters with the name
89
+ `api_key`.
90
+ END
91
+ },
92
+ )
93
+ end
94
+
58
95
  def test
59
- render api_response({message: "Test successful!"})
96
+ return api_response({message: "Hello, world!"})
60
97
  end
61
98
  end
62
99
  ```
63
100
 
64
- `ModelControllerMixin` assists with providing the standard model CRUD for your controller.
101
+ And here is an example of a resource controller:
65
102
 
66
103
  ```ruby
67
104
  class Api::MoviesController < ApiController
68
105
  include RESTFramework::ModelControllerMixin
69
106
 
70
- self.recordset = Movie.where(enabled: true)
107
+ self.fields = [:id, :name, :release_date, :enabled]
108
+ self.extra_member_actions = {first: :get}
109
+
110
+ def first
111
+ # Always use the bang method, since the framework will rescue `RecordNotFound` and return a
112
+ # sensible error response.
113
+ return api_response(self.get_records.first!)
114
+ end
115
+
116
+ def get_recordset
117
+ return Movie.where(enabled: true)
118
+ end
71
119
  end
72
120
  ```
73
121
 
74
- `ReadOnlyModelControllerMixin` only enables list/show actions, but since we're naming this
75
- controller in a way that doesn't make the model obvious, we can set that explicitly:
122
+ You can also configure a resource's fields dynamically using `include` and `exclude` keys:
76
123
 
77
124
  ```ruby
78
- class Api::ReadOnlyMoviesController < ApiController
79
- include RESTFramework::ReadOnlyModelControllerMixin
125
+ class Api::UsersController < ApiController
126
+ include RESTFramework::ModelControllerMixin
80
127
 
81
- self.model = Movie
128
+ self.fields = {include: [:calculated_popularity], exclude: [:impersonation_token]}
82
129
  end
83
130
  ```
84
131
 
85
- Note that you can also override the `get_recordset` instance method to override the API behavior
86
- dynamically per-request.
87
-
88
132
  ### Routing
89
133
 
90
134
  You can use Rails' `resource`/`resources` routers to route your API, however if you want
91
135
  `extra_actions` / `extra_member_actions` to be routed automatically, then you can use `rest_route`
92
- for non-resourceful controllers, or `rest_resource` / `rest_resources` resourceful routers. You can
93
- also use `rest_root` to route the root of your API:
136
+ for non-resourceful controllers, or `rest_resource` / `rest_resources` resourceful routers. To route
137
+ the root, use `rest_root`.
94
138
 
95
139
  ```ruby
96
140
  Rails.application.routes.draw do
97
- rest_root :api # will find `api_controller` and route the `root` action to '/api'
98
- namespace :api do
99
- rest_resources :movies
100
- rest_resources :users
101
- end
102
- end
103
- ```
104
-
105
- Or if you want the API root to be routed to `Api::RootController#root`:
141
+ # If you wanted to route actions from the `ApiController`, then you would use this:
142
+ # rest_root :api # Will find `api_controller` and route the `root` action to '/api'.
106
143
 
107
- ```ruby
108
- Rails.application.routes.draw do
109
144
  namespace :api do
110
- rest_root # will route `Api::RootController#root` to '/' in this namespace ('/api')
145
+ rest_root # Will route `Api::RootController#root` to '/' in this namespace ('/api').
111
146
  rest_resources :movies
112
147
  rest_resources :users
113
148
  end
@@ -117,14 +152,7 @@ end
117
152
  ## Development/Testing
118
153
 
119
154
  After you clone the repository, cd'ing into the directory should create a new gemset if you are
120
- using RVM. Then run `bundle install` to install the appropriate gems.
121
-
122
- To run the test suite:
123
-
124
- ```shell
125
- $ rails test
126
- ```
155
+ using RVM. Then run `bin/setup` to install the appropriate gems and set things up.
127
156
 
128
157
  The top-level `bin/rails` proxies all Rails commands to the test project, so you can operate it via
129
- the usual commands. Ensure you run `rails db:setup` before running `rails server` or
130
- `rails console`.
158
+ the usual commands (e.g., `rails test`, `rails server` and `rails console`).
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.8
1
+ 0.9.9
@@ -29,7 +29,6 @@
29
29
  h1, h2, h3, h4, h5, h6 {
30
30
  color: var(--rrf-red);
31
31
  font-weight: normal;
32
- margin-bottom: 0;
33
32
  }
34
33
  html[data-bs-theme="dark"] h1,
35
34
  html[data-bs-theme="dark"] h2,
@@ -290,7 +289,7 @@
290
289
 
291
290
  // Convert plain-text links to anchor tag links.
292
291
  function rrfLinkify(text) {
293
- return text.replace(/(https?:\/\/[^\s<>"]+)/g, "<a href=\"$1\" target=\"_blank\">$1</a>")
292
+ return text.replace(/(https?:\/\/[^\s<>"]+)/g, "<a href=\"$1\">$1</a>")
294
293
  }
295
294
 
296
295
  // Replace the document when doing form submission (mainly to support PUT/PATCH/DELETE).
@@ -1,7 +1,7 @@
1
1
  <div class="row">
2
2
  <div>
3
3
  <%= render partial: "rest_framework/heading/actions" if @route_groups.present? %>
4
- <h1 class="m-0"><%= @heading_title || @title %></h1>
4
+ <h1 style="margin: 0"><%= @heading_title || @title %></h1>
5
5
  <% if @description.present? %>
6
6
  <br><br><p style="display: inline-block; margin-bottom: 0"><%= @description %></p>
7
7
  <% end %>
@@ -17,7 +17,7 @@
17
17
  <% end %>
18
18
  </ul>
19
19
  </div>
20
- <div class="tab-content pt-2">
20
+ <div class="tab-content">
21
21
  <div class="tab-pane fade show active" id="tab-json" role="tabpanel">
22
22
  <% if @json_payload.present? %>
23
23
  <div><pre class="rrf-copy"><code class="language-json"><%=
@@ -1,16 +1,14 @@
1
1
  <div class="row">
2
2
  <div>
3
- <pre><code><%
3
+ <pre class="mb-2"><code class="language-plaintext"><%
4
4
  concat request.request_method
5
5
  if request.method != request.request_method
6
6
  concat " (via #{request.method})"
7
7
  end
8
8
  concat " #{request.path}"
9
9
  %></code></pre>
10
- <pre><code><%
10
+ <pre><code class="language-plaintext"><%
11
11
  concat "HTTP #{response.status} #{response.message}"
12
- concat "\n"
13
- concat "Content-Type: #{response.content_type}"
14
12
  %></code></pre>
15
13
  </div>
16
14
  </div>
@@ -34,7 +34,7 @@
34
34
  <% end %>
35
35
  </ul>
36
36
  </div>
37
- <div class="tab-content pt-2">
37
+ <div class="tab-content">
38
38
  <div class="tab-pane fade show active" id="tab-routes" role="tabpanel">
39
39
  <%= render partial: "rest_framework/routes_and_forms/routes" %>
40
40
  </div>
@@ -49,4 +49,4 @@
49
49
  </div>
50
50
  <% end %>
51
51
  </div>
52
- </div>
52
+ </div>
@@ -0,0 +1,5 @@
1
+ class RESTFramework::Errors::BaseError < StandardError
2
+ end
3
+
4
+ # Alias for convenience.
5
+ RESTFramework::BaseError = RESTFramework::Errors::BaseError
@@ -0,0 +1,14 @@
1
+ class RESTFramework::Errors::NilPassedToAPIResponseError < RESTFramework::Errors::BaseError
2
+ def message
3
+ return <<~MSG.split("\n").join(" ")
4
+ Payload of `nil` was passed to `api_response`; this is unsupported. If you want a blank
5
+ response, pass `''` (an empty string) as the payload. If this was the result of a `find_by`
6
+ (or similar Active Record method) not finding a record, you should use the bang version (e.g.,
7
+ `find_by!`) to raise `ActiveRecord::RecordNotFound`, which the REST controller will catch and
8
+ return an appropriate error response.
9
+ MSG
10
+ end
11
+ end
12
+
13
+ # Alias for convenience.
14
+ RESTFramework::NilPassedToAPIResponseError = RESTFramework::Errors::NilPassedToAPIResponseError
@@ -0,0 +1,18 @@
1
+ class RESTFramework::Errors::UnknownModelError < RESTFramework::Errors::BaseError
2
+ def initialize(controller_class)
3
+ super()
4
+ @controller_class = controller_class
5
+ end
6
+
7
+ def message
8
+ return <<~MSG.split("\n").join(" ")
9
+ The model class for `#{@controller_class}` could not be determined. Any controller that
10
+ includes `RESTFramework::BaseModelControllerMixin` (directly or indirectly) must either set
11
+ the `model` attribute on the controller, or the model must be deducible from the controller
12
+ name (e.g., `UsersController` could resolve to the `User` model).
13
+ MSG
14
+ end
15
+ end
16
+
17
+ # Alias for convenience.
18
+ RESTFramework::UnknownModelError = RESTFramework::Errors::UnknownModelError
@@ -1,31 +1,7 @@
1
- # Top-level class for all REST Framework errors.
2
- class RESTFramework::Error < StandardError
1
+ module RESTFramework::Errors
3
2
  end
4
3
 
5
- class RESTFramework::NilPassedToAPIResponseError < RESTFramework::Error
6
- def message
7
- return <<~MSG.split("\n").join(" ")
8
- Payload of `nil` was passed to `api_response`; this is unsupported. If you want a blank
9
- response, pass `''` (an empty string) as the payload. If this was the result of a `find_by`
10
- (or similar Active Record method) not finding a record, you should use the bang version (e.g.,
11
- `find_by!`) to raise `ActiveRecord::RecordNotFound`, which the REST controller will catch and
12
- return an appropriate error response.
13
- MSG
14
- end
15
- end
16
-
17
- class RESTFramework::UnknownModelError < RESTFramework::Error
18
- def initialize(controller_class)
19
- super()
20
- @controller_class = controller_class
21
- end
4
+ require_relative "errors/base_error"
22
5
 
23
- def message
24
- return <<~MSG.split("\n").join(" ")
25
- The model class for `#{@controller_class}` could not be determined. Any controller that
26
- includes `RESTFramework::BaseModelControllerMixin` (directly or indirectly) must either set
27
- the `model` attribute on the controller, or the model must be deducible from the controller
28
- name (e.g., `UsersController` could resolve to the `User` model).
29
- MSG
30
- end
31
- end
6
+ require_relative "errors/nil_passed_to_api_response_error"
7
+ require_relative "errors/unknown_model_error"
@@ -31,9 +31,6 @@ module RESTFramework::Mixins::BulkCreateModelMixin
31
31
  end
32
32
  end
33
33
 
34
- # Alias for convenience.
35
- RESTFramework::BulkCreateModelMixin = RESTFramework::Mixins::BulkCreateModelMixin
36
-
37
34
  # Mixin for updating records in bulk.
38
35
  module RESTFramework::Mixins::BulkUpdateModelMixin
39
36
  def update_all
@@ -59,9 +56,6 @@ module RESTFramework::Mixins::BulkUpdateModelMixin
59
56
  end
60
57
  end
61
58
 
62
- # Alias for convenience.
63
- RESTFramework::BulkUpdateModelMixin = RESTFramework::Mixins::BulkUpdateModelMixin
64
-
65
59
  # Mixin for destroying records in bulk.
66
60
  module RESTFramework::Mixins::BulkDestroyModelMixin
67
61
  def destroy_all
@@ -89,21 +83,21 @@ module RESTFramework::Mixins::BulkDestroyModelMixin
89
83
  end
90
84
  end
91
85
 
92
- # Alias for convenience.
93
- RESTFramework::BulkDestroyModelMixin = RESTFramework::Mixins::BulkDestroyModelMixin
94
-
95
86
  # Mixin that includes all the CRUD bulk mixins.
96
87
  module RESTFramework::Mixins::BulkModelControllerMixin
97
- include RESTFramework::ModelControllerMixin
88
+ include RESTFramework::Mixins::ModelControllerMixin
98
89
 
99
- include RESTFramework::BulkCreateModelMixin
100
- include RESTFramework::BulkUpdateModelMixin
101
- include RESTFramework::BulkDestroyModelMixin
90
+ include RESTFramework::Mixins::BulkCreateModelMixin
91
+ include RESTFramework::Mixins::BulkUpdateModelMixin
92
+ include RESTFramework::Mixins::BulkDestroyModelMixin
102
93
 
103
94
  def self.included(base)
104
- RESTFramework::ModelControllerMixin.included(base)
95
+ RESTFramework::Mixins::ModelControllerMixin.included(base)
105
96
  end
106
97
  end
107
98
 
108
- # Alias for convenience.
99
+ # Aliases for convenience.
100
+ RESTFramework::BulkCreateModelMixin = RESTFramework::Mixins::BulkCreateModelMixin
101
+ RESTFramework::BulkUpdateModelMixin = RESTFramework::Mixins::BulkUpdateModelMixin
102
+ RESTFramework::BulkDestroyModelMixin = RESTFramework::Mixins::BulkDestroyModelMixin
109
103
  RESTFramework::BulkModelControllerMixin = RESTFramework::Mixins::BulkModelControllerMixin
@@ -631,9 +631,6 @@ module RESTFramework::Mixins::BaseModelControllerMixin
631
631
  end
632
632
  end
633
633
 
634
- # Alias for convenience.
635
- RESTFramework::BaseModelControllerMixin = RESTFramework::Mixins::BaseModelControllerMixin
636
-
637
634
  # Mixin for listing records.
638
635
  module RESTFramework::Mixins::ListModelMixin
639
636
  def index
@@ -662,9 +659,6 @@ module RESTFramework::Mixins::ListModelMixin
662
659
  end
663
660
  end
664
661
 
665
- # Alias for convenience.
666
- RESTFramework::ListModelMixin = RESTFramework::Mixins::ListModelMixin
667
-
668
662
  # Mixin for showing records.
669
663
  module RESTFramework::Mixins::ShowModelMixin
670
664
  def show
@@ -672,9 +666,6 @@ module RESTFramework::Mixins::ShowModelMixin
672
666
  end
673
667
  end
674
668
 
675
- # Alias for convenience.
676
- RESTFramework::ShowModelMixin = RESTFramework::Mixins::ShowModelMixin
677
-
678
669
  # Mixin for creating records.
679
670
  module RESTFramework::Mixins::CreateModelMixin
680
671
  def create
@@ -687,9 +678,6 @@ module RESTFramework::Mixins::CreateModelMixin
687
678
  end
688
679
  end
689
680
 
690
- # Alias for convenience.
691
- RESTFramework::CreateModelMixin = RESTFramework::Mixins::CreateModelMixin
692
-
693
681
  # Mixin for updating records.
694
682
  module RESTFramework::Mixins::UpdateModelMixin
695
683
  def update
@@ -704,9 +692,6 @@ module RESTFramework::Mixins::UpdateModelMixin
704
692
  end
705
693
  end
706
694
 
707
- # Alias for convenience.
708
- RESTFramework::UpdateModelMixin = RESTFramework::Mixins::UpdateModelMixin
709
-
710
695
  # Mixin for destroying records.
711
696
  module RESTFramework::Mixins::DestroyModelMixin
712
697
  def destroy
@@ -720,38 +705,39 @@ module RESTFramework::Mixins::DestroyModelMixin
720
705
  end
721
706
  end
722
707
 
723
- # Alias for convenience.
724
- RESTFramework::DestroyModelMixin = RESTFramework::Mixins::DestroyModelMixin
725
-
726
708
  # Mixin that includes show/list mixins.
727
709
  module RESTFramework::Mixins::ReadOnlyModelControllerMixin
728
- include RESTFramework::BaseModelControllerMixin
710
+ include RESTFramework::Mixins::BaseModelControllerMixin
729
711
 
730
- include RESTFramework::ListModelMixin
731
- include RESTFramework::ShowModelMixin
712
+ include RESTFramework::Mixins::ListModelMixin
713
+ include RESTFramework::Mixins::ShowModelMixin
732
714
 
733
715
  def self.included(base)
734
716
  RESTFramework::BaseModelControllerMixin.included(base)
735
717
  end
736
718
  end
737
719
 
738
- # Alias for convenience.
739
- RESTFramework::ReadOnlyModelControllerMixin = RESTFramework::Mixins::ReadOnlyModelControllerMixin
740
-
741
720
  # Mixin that includes all the CRUD mixins.
742
721
  module RESTFramework::Mixins::ModelControllerMixin
743
- include RESTFramework::BaseModelControllerMixin
722
+ include RESTFramework::Mixins::BaseModelControllerMixin
744
723
 
745
- include RESTFramework::ListModelMixin
746
- include RESTFramework::ShowModelMixin
747
- include RESTFramework::CreateModelMixin
748
- include RESTFramework::UpdateModelMixin
749
- include RESTFramework::DestroyModelMixin
724
+ include RESTFramework::Mixins::ListModelMixin
725
+ include RESTFramework::Mixins::ShowModelMixin
726
+ include RESTFramework::Mixins::CreateModelMixin
727
+ include RESTFramework::Mixins::UpdateModelMixin
728
+ include RESTFramework::Mixins::DestroyModelMixin
750
729
 
751
730
  def self.included(base)
752
731
  RESTFramework::BaseModelControllerMixin.included(base)
753
732
  end
754
733
  end
755
734
 
756
- # Alias for convenience.
735
+ # Aliases for convenience.
736
+ RESTFramework::BaseModelControllerMixin = RESTFramework::Mixins::BaseModelControllerMixin
737
+ RESTFramework::ListModelMixin = RESTFramework::Mixins::ListModelMixin
738
+ RESTFramework::ShowModelMixin = RESTFramework::Mixins::ShowModelMixin
739
+ RESTFramework::CreateModelMixin = RESTFramework::Mixins::CreateModelMixin
740
+ RESTFramework::UpdateModelMixin = RESTFramework::Mixins::UpdateModelMixin
741
+ RESTFramework::DestroyModelMixin = RESTFramework::Mixins::DestroyModelMixin
742
+ RESTFramework::ReadOnlyModelControllerMixin = RESTFramework::Mixins::ReadOnlyModelControllerMixin
757
743
  RESTFramework::ModelControllerMixin = RESTFramework::Mixins::ModelControllerMixin
@@ -59,13 +59,24 @@ class RESTFramework::Paginators::PageNumberPaginator < RESTFramework::Paginators
59
59
 
60
60
  # Wrap the serialized page with appropriate metadata. TODO: include links.
61
61
  def get_paginated_response(serialized_page)
62
+ page_query_param = @controller.page_query_param
63
+ base_params = @controller.params.to_unsafe_h
64
+ next_url = if @page_number < @total_pages
65
+ @controller.url_for({**base_params, page_query_param => @page_number + 1})
66
+ end
67
+ previous_url = if @page_number > 1
68
+ @controller.url_for({**base_params, page_query_param => @page_number - 1})
69
+ end
70
+
62
71
  return {
63
72
  count: @count,
64
73
  page: @page_number,
65
74
  page_size: @page_size,
66
75
  total_pages: @total_pages,
76
+ next: next_url,
77
+ previous: previous_url,
67
78
  results: serialized_page,
68
- }
79
+ }.compact
69
80
  end
70
81
  end
71
82
 
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.8
4
+ version: 0.9.9
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-07 00:00:00.000000000 Z
11
+ date: 2023-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -53,6 +53,9 @@ files:
53
53
  - lib/rest_framework.rb
54
54
  - lib/rest_framework/engine.rb
55
55
  - lib/rest_framework/errors.rb
56
+ - lib/rest_framework/errors/base_error.rb
57
+ - lib/rest_framework/errors/nil_passed_to_api_response_error.rb
58
+ - lib/rest_framework/errors/unknown_model_error.rb
56
59
  - lib/rest_framework/filters.rb
57
60
  - lib/rest_framework/filters/base_filter.rb
58
61
  - lib/rest_framework/filters/model_ordering_filter.rb