rest_framework 0.9.2 → 0.9.3

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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/app/views/rest_framework/_external.html.erb +13 -0
  4. data/app/views/rest_framework/_head.html.erb +2 -192
  5. data/{docs/assets/js/rest_framework.js → app/views/rest_framework/_shared.html} +69 -42
  6. data/docs/Gemfile +1 -0
  7. data/docs/Gemfile.lock +14 -14
  8. data/docs/_config.yml +4 -2
  9. data/docs/_guide/2_controllers.md +342 -0
  10. data/docs/_guide/3_serializers.md +1 -1
  11. data/docs/_guide/4_filtering_and_ordering.md +8 -8
  12. data/docs/_includes/external.html +9 -0
  13. data/docs/_includes/head.html +135 -15
  14. data/docs/_includes/shared.html +164 -0
  15. data/lib/rest_framework/controller_mixins/base.rb +23 -36
  16. data/lib/rest_framework/controller_mixins/models.rb +86 -75
  17. data/lib/rest_framework/controller_mixins.rb +1 -0
  18. data/lib/rest_framework/engine.rb +9 -0
  19. data/lib/rest_framework/filters/base.rb +9 -0
  20. data/lib/rest_framework/filters/model_ordering.rb +48 -0
  21. data/lib/rest_framework/filters/model_query.rb +51 -0
  22. data/lib/rest_framework/filters/model_search.rb +41 -0
  23. data/lib/rest_framework/filters/ransack.rb +25 -0
  24. data/lib/rest_framework/filters.rb +6 -150
  25. data/lib/rest_framework/paginators.rb +7 -11
  26. data/lib/rest_framework/serializers.rb +10 -10
  27. data/lib/rest_framework/utils.rb +15 -7
  28. data/lib/rest_framework.rb +93 -4
  29. data/vendor/assets/javascripts/rest_framework/bootstrap.js +7 -0
  30. data/vendor/assets/javascripts/rest_framework/highlight-json.js +7 -0
  31. data/vendor/assets/javascripts/rest_framework/highlight-xml.js +29 -0
  32. data/vendor/assets/javascripts/rest_framework/highlight.js +1202 -0
  33. data/vendor/assets/javascripts/rest_framework/neatjson.js +8 -0
  34. data/vendor/assets/javascripts/rest_framework/trix.js +6 -0
  35. data/vendor/assets/stylesheets/rest_framework/bootstrap-icons.css +13 -0
  36. data/vendor/assets/stylesheets/rest_framework/bootstrap.css +6 -0
  37. data/vendor/assets/stylesheets/rest_framework/highlight-a11y-dark.css +7 -0
  38. data/vendor/assets/stylesheets/rest_framework/highlight-a11y-light.css +7 -0
  39. data/vendor/assets/stylesheets/rest_framework/trix.css +410 -0
  40. metadata +23 -5
  41. data/docs/_guide/2_controller_mixins.md +0 -293
  42. data/docs/assets/css/rest_framework.css +0 -159
@@ -1,293 +0,0 @@
1
- ---
2
- layout: default
3
- title: Controller Mixins
4
- position: 2
5
- slug: controller-mixins
6
- ---
7
- # Controller Mixins
8
-
9
- This is the core of the REST Framework. Generally speaking, projects already have an existing
10
- controller inheritance hierarchy, so we want developers to be able to maintain that project
11
- structure while leveraging the power of the REST Framework. Also, different controllers which
12
- inherit from the same parent often need different REST Framework mixins. For these reasons, REST
13
- Framework provides the controller functionality as modules that you mix into your controllers.
14
-
15
- ## Response Rendering
16
-
17
- Before we go into the various controller mixins, one of the core capabilities of the REST Framework
18
- is to provide system-consumable responses along side a browsable API for developers. While you can
19
- use Rails' builtin rendering tools, such as `render`, the REST Framework provides a rendering helper
20
- called `api_response`. This helper allows you to return a browsable API response for the `html`
21
- format which shows you what the JSON/XML response would look like, along with faster and lighter
22
- responses for `json` and `xml` formats.
23
-
24
- Here is an example:
25
-
26
- ```ruby
27
- class ApiController < ApplicationController
28
- include RESTFramework::BaseControllerMixin
29
- self.extra_actions = {test: :get}
30
-
31
- def test
32
- api_response({message: "Test successful!"})
33
- end
34
- end
35
- ```
36
-
37
- ## `BaseControllerMixin`
38
-
39
- To transform a controller into the simplest possible RESTful controller, you can include
40
- `BaseControllerMixin`, which provides a simple `root` action so it can be used at the API root.
41
-
42
- ```ruby
43
- class ApiController < ApplicationController
44
- include RESTFramework::BaseControllerMixin
45
- end
46
- ```
47
-
48
- ### Controller Attributes
49
-
50
- You can customize the behavior of `BaseControllerMixin` by setting or mutating various class
51
- attributes.
52
-
53
- #### `singleton_controller`
54
-
55
- This property primarily controls the routes that are generated for a RESTful controller. If you use
56
- `api_resource`/`api_resources` to define whether the generates routes are for a collection or for
57
- a single member, then you do not need to use this property. However, if you are autogenerating those
58
- routers, then `singleton_controller` will tell REST Framework whether to provide collection routes
59
- (when `singleton_controller` is falsy) or member routes (when `singleton_controller` is truthy). To
60
- read more about singular vs plural routing, see Rails' documentation here:
61
- https://guides.rubyonrails.org/routing.html#singular-resources.
62
-
63
- #### `extra_actions`
64
-
65
- This property defines extra actions on the controller to be routed. It is a hash of
66
- `endpoint -> method(s)` (where `method(s)` can be a method symbol or an array of method symbols).
67
-
68
- ```ruby
69
- class ApiController < ApplicationController
70
- include RESTFramework::BaseControllerMixin
71
- self.extra_actions = {test: :get}
72
-
73
- def test
74
- api_response({message: "Test successful!"})
75
- end
76
- end
77
- ```
78
-
79
- Or with multiple methods:
80
-
81
- ```ruby
82
- class ApiController < ApplicationController
83
- include RESTFramework::BaseControllerMixin
84
- self.extra_actions = {test: [:get, :post]}
85
-
86
- def test
87
- api_response({message: "Test successful!"})
88
- end
89
- end
90
- ```
91
-
92
- If your action conflicts with a builtin method, then you can also override the path:
93
-
94
- ```ruby
95
- class ApiController < ApplicationController
96
- include RESTFramework::BaseControllerMixin
97
-
98
- # This will route `test_action` to `/test`, in case there is already a `test` method that cannot
99
- # be overridden.
100
- self.extra_actions = {test_action: {path: :test, methods: :get}}
101
-
102
- def test_action
103
- api_response({message: "Test successful!"})
104
- end
105
- end
106
- ```
107
-
108
- ## `ModelControllerMixin`
109
-
110
- `ModelControllerMixin` assists with providing the standard model CRUD (create, read, update,
111
- destroy) for your controller. This is the most commonly used mixin since it provides default
112
- behavior for models which matches Rails' default routing.
113
-
114
- ```ruby
115
- class Api::MoviesController < ApiController
116
- include RESTFramework::ModelControllerMixin
117
- end
118
- ```
119
-
120
- By default, all columns and associations are included in `self.fields`, which can be helpful when
121
- developing an administrative API. For user-facing APIs, however, `self.fields` should always be
122
- explicitly defined.
123
-
124
- ### Controller Attributes
125
-
126
- You can customize the behavior of `ModelControllerMixin` by setting or mutating various class
127
- attributes.
128
-
129
- #### `model`
130
-
131
- The `model` property allows you to define the model if it is not obvious from the controller name.
132
-
133
- ```ruby
134
- class Api::CoolMoviesController < ApiController
135
- include RESTFramework::ModelControllerMixin
136
-
137
- self.model = Movie
138
- end
139
- ```
140
-
141
- #### `recordset`
142
-
143
- The `recordset` property allows you to define the set of records this API should be limited to. If
144
- you need to change the recordset based on properties of the request, then you can override the
145
- `get_recordset()` method.
146
-
147
- ```ruby
148
- class Api::CoolMoviesController < ApiController
149
- include RESTFramework::ModelControllerMixin
150
-
151
- self.recordset = Movie.where(cool: true).order({id: :asc})
152
- end
153
- ```
154
-
155
- #### `extra_member_actions`
156
-
157
- The `extra_member_actions` property allows you to define additional actions on individual records.
158
-
159
- ```ruby
160
- class Api::MoviesController < ApiController
161
- include RESTFramework::ModelControllerMixin
162
-
163
- self.extra_member_actions = {disable: :post}
164
-
165
- def disable
166
- @record = self.get_record # REST Framework will rescue ActiveRecord::RecordNotFound
167
-
168
- # REST Framework will rescue ActiveRecord::RecordInvalid or ActiveRecord::RecordNotSaved
169
- @record.update!(enabled: false)
170
-
171
- return api_response(@record)
172
- end
173
- end
174
- ```
175
-
176
- #### `fields`
177
-
178
- The `fields` property defines the default fields for serialization and for parameters allowed from
179
- the body or query string.
180
-
181
- ```ruby
182
- class Api::MoviesController < ApiController
183
- include RESTFramework::ModelControllerMixin
184
-
185
- self.fields = [:id, :name]
186
- end
187
- ```
188
-
189
- #### `action_fields`
190
-
191
- The `action_fields` property is similar to `fields`, but allows you to define different fields for
192
- different actions. A good example is to serialize expensive computed properties only in the `show`
193
- action, but not in the `list` action (where many records are serialized).
194
-
195
- ```ruby
196
- class Api::MoviesController < ApiController
197
- include RESTFramework::ModelControllerMixin
198
-
199
- self.fields = [:id, :name]
200
- self.action_fields = {
201
- show: [:id, :name, :some_expensive_computed_property],
202
- }
203
- end
204
- ```
205
-
206
- #### `native_serializer_config`
207
-
208
- These properties define the serializer configuration if you are using the native `ActiveModel`
209
- serializer. You can also specify serializers for singular/plural
210
-
211
- ```ruby
212
- class Api::MoviesController < ApiController
213
- include RESTFramework::ModelControllerMixin
214
-
215
- self.native_serializer_config = {
216
- only: [:id, :name],
217
- methods: [:active, :some_expensive_computed_property],
218
- include: {cast_members: { only: [:id, :name], methods: [:net_worth] }},
219
- }
220
-
221
- # Or you could configure a default and a plural serializer:
222
- self.native_serializer_plural_config = {
223
- only: [:id, :name],
224
- methods: [:active],
225
- include: {cast_members: { only: [:id, :name], methods: [:net_worth] }},
226
- }
227
- self.native_serializer_config = {
228
- only: [:id, :name],
229
- methods: [:active, :some_expensive_computed_property],
230
- include: {cast_members: { only: [:id, :name], methods: [:net_worth] }},
231
- }
232
-
233
- # Or you could configure a default and a singular serializer:
234
- self.native_serializer_config = {
235
- only: [:id, :name],
236
- methods: [:active],
237
- include: {cast_members: { only: [:id, :name], methods: [:net_worth] }},
238
- }
239
- self.native_serializer_singular_config = {
240
- only: [:id, :name],
241
- methods: [:active, :some_expensive_computed_property],
242
- include: {cast_members: { only: [:id, :name], methods: [:net_worth] }},
243
- }
244
- end
245
- ```
246
-
247
- #### `allowed_parameters` / `allowed_action_parameters`
248
-
249
- These properties define the permitted parameters to be used in the request body for create/update
250
- actions. If you need different allowed parameters, then you can also override the
251
- `get_create_params` or `get_update_params` methods.
252
-
253
- ```ruby
254
- class Api::MoviesController < ApiController
255
- include RESTFramework::ModelControllerMixin
256
-
257
- self.allowed_parameters = [:name]
258
- end
259
- ```
260
-
261
- #### `create_from_recordset` (default: `true`)
262
-
263
- The `create_from_recordset` attribute (`true` by default) is a boolean to control the behavior in
264
- the `create` action. If it is disabled, records will not be created from the filtered recordset, but
265
- rather will be created directly from the model interface.
266
-
267
- For example, if this is your controller:
268
-
269
- ```ruby
270
- class Api::CoolMoviesController < ApiController
271
- include RESTFramework::ModelControllerMixin
272
-
273
- def get_recordset
274
- return Movie.where(cool: true)
275
- end
276
- end
277
- ```
278
-
279
- Then if you hit the `create` action with the payload `{name: "Superman"}`, it will also set `cool`
280
- to `true` on the new record, because that property is inherited from the recordset.
281
-
282
- ## `ReadOnlyModelControllerMixin`
283
-
284
- `ReadOnlyModelControllerMixin` only enables list/show actions. In this example, since we're naming
285
- this controller in a way that doesn't make the model obvious, we can set that explicitly:
286
-
287
- ```ruby
288
- class Api::ReadOnlyMoviesController < ApiController
289
- include RESTFramework::ReadOnlyModelControllerMixin
290
-
291
- self.model = Movie
292
- end
293
- ```
@@ -1,159 +0,0 @@
1
- /********************************
2
- * START OF LIB/DOCS COMMON CSS *
3
- ********************************/
4
-
5
- :root {
6
- --rrf-red: #900;
7
- --rrf-red-hover: #5f0c0c;
8
- --rrf-light-red: #db2525;
9
- --rrf-light-red-hover: #b80404;
10
- }
11
- #rrfAccentBar {
12
- background-color: var(--rrf-red);
13
- height: .3em;
14
- }
15
- header nav { background-color: black; }
16
-
17
- /* Header adjustments. */
18
- h1 { font-size: 2rem; }
19
- h2 { font-size: 1.7rem; }
20
- h3 { font-size: 1.5rem; }
21
- h4 { font-size: 1.3rem; }
22
- h5 { font-size: 1.1rem; }
23
- h6 { font-size: 1rem; }
24
- h1, h2, h3, h4, h5, h6 {
25
- color: var(--rrf-red);
26
- }
27
- html[data-bs-theme="dark"] h1,
28
- html[data-bs-theme="dark"] h2,
29
- html[data-bs-theme="dark"] h3,
30
- html[data-bs-theme="dark"] h4,
31
- html[data-bs-theme="dark"] h5,
32
- html[data-bs-theme="dark"] h6 {
33
- color: var(--rrf-light-red);
34
- }
35
-
36
- /* Improve code and code blocks. */
37
- pre code {
38
- display: block;
39
- overflow-x: auto;
40
- }
41
- code, .trix-content pre {
42
- padding: .5em !important;
43
- background-color: #eee !important;
44
- border: 1px solid #aaa;
45
- border-radius: 3px;
46
- }
47
- p code {
48
- padding: .1em .3em !important;
49
- }
50
- html[data-bs-theme="dark"] code, html[data-bs-theme="dark"] .trix-content pre {
51
- background-color: #2b2b2b !important;
52
- }
53
-
54
- /* Anchors */
55
- a:not(.nav-link) {
56
- text-decoration: none;
57
- color: var(--rrf-red);
58
- }
59
- a:hover:not(.nav-link) {
60
- text-decoration: underline;
61
- color: var(--rrf-red-hover);
62
- }
63
- html[data-bs-theme="dark"] a:not(.nav-link) { color: var(--rrf-light-red); }
64
- html[data-bs-theme="dark"] a:hover:not(.nav-link) { color: var(--rrf-light-red-hover); }
65
-
66
- /******************************
67
- * END OF LIB/DOCS COMMON CSS *
68
- ******************************/
69
-
70
- /* Header adjustments. */
71
- h1, h2, h3, h4, h5, h6 {
72
- width: 100%;
73
- font-weight: normal;
74
- margin-top: 1.8rem;
75
- margin-bottom: 1.2rem;
76
- }
77
- h1 a:not(:hover),
78
- h2 a:not(:hover),
79
- h3 a:not(:hover),
80
- h4 a:not(:hover),
81
- h5 a:not(:hover),
82
- h6 a:not(:hover) {
83
- color: #ddd;
84
- }
85
- html[data-bs-theme="dark"] h1 a:not(:hover),
86
- html[data-bs-theme="dark"] h2 a:not(:hover),
87
- html[data-bs-theme="dark"] h3 a:not(:hover),
88
- html[data-bs-theme="dark"] h4 a:not(:hover),
89
- html[data-bs-theme="dark"] h5 a:not(:hover),
90
- html[data-bs-theme="dark"] h6 a:not(:hover) {
91
- color: #444;
92
- }
93
- h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover {
94
- text-decoration: none !important;
95
- }
96
-
97
- /* Navbar */
98
- .navbar .navbar-toggler {
99
- margin: .2em 0;
100
- padding: .2em .3em;
101
- border: none;
102
- }
103
- .navbar .navbar-toggler .navbar-toggler-icon {
104
- height: 1.1em;
105
- width: 1.1em;
106
- }
107
- .navbar .navbar-nav .nav-item .nav-link {
108
- padding: .45em .6em;
109
- }
110
- .navbar .navbar-nav .nav-item .nav-link:hover {
111
- background-color: #262a2f;
112
- }
113
- .navbar .dropdown-menu a.dropdown-item {
114
- font-size: .9em;
115
- padding: .2em .8em;
116
- }
117
-
118
- /* Headers table. */
119
- .headers-table {
120
- padding: .5em 1em;
121
- background-color: #eee;
122
- border: 1px solid #aaa;
123
- border-radius: .3em;
124
- font-size: .9em;
125
- }
126
- html[data-bs-theme="dark"] .headers-table {
127
- background-color: #2b2b2b;
128
- }
129
- .headers-table:empty { display: none; }
130
- .headers-table ul {
131
- list-style-type: none;
132
- margin: 0;
133
- padding-left: 0;
134
- padding-right: .6em;
135
- }
136
- .headers-table ul li { margin: .3em 0; }
137
- .headers-table ul ul { padding-left: .8em; padding-right: 0; }
138
- .headers-table > ul > li {
139
- font-weight: bold;
140
- }
141
-
142
- /* Style the github and mode component. */
143
- #rrfGithubAndModeWrapper {
144
- height: 2.4em;
145
- }
146
- #rrfGithubComponent {
147
- display: inline-block;
148
- position: relative;
149
- top: .6em;
150
- }
151
- #rrfModeComponent .dropdown-toggle {
152
- float: right;
153
- }
154
- #rrfModeComponent .dropdown-menu {
155
- position: absolute;
156
- right: 0;
157
- left: auto;
158
- top: 100%;
159
- }