rest_framework 0.0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +77 -5
- data/lib/rest_framework/VERSION_STAMP +1 -1
- data/lib/rest_framework/controllers/base.rb +20 -1
- data/lib/rest_framework/controllers/models.rb +9 -6
- data/lib/rest_framework/routers.rb +12 -7
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ae8173bd8209fe5250ec9fe3a749d41d46307f7948d1c7597921ab5b4d2cae2
|
4
|
+
data.tar.gz: 3ca1aa88dbde70ad327a65778bfa7e2a90499111dbf6e16a9d084aba2df42328
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd56096773684dc55324b6a8d3fed2a7d214201fd9ac516862a24a111ecedcf70cebf20b61ff264f11a921d67e9a057da4a8b1c2d4c498d07bb042401993e5e3
|
7
|
+
data.tar.gz: 2f9f5b01fa4a956f0047307ed0f9b7523607ad6487fa5f8fa15d9895b7ff814703c048e5a7a0261fad35f11b96f3078641e8b9dd9e897bdbbc15b36c775c084e
|
data/README.md
CHANGED
@@ -24,6 +24,78 @@ Or install it yourself with:
|
|
24
24
|
|
25
25
|
$ gem install rest_framework
|
26
26
|
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
### Controller Mixins
|
30
|
+
|
31
|
+
To transform a controller into a RESTful controller, you can either include `BaseControllerMixin`,
|
32
|
+
`ReadOnlyModelControllerMixin`, or `ModelControllerMixin`. `BaseControllerMixin` provides a `root`
|
33
|
+
action and a simple interface for routing arbitrary additional actions:
|
34
|
+
|
35
|
+
```
|
36
|
+
class ApiController < ApplicationController
|
37
|
+
include RESTFramework::BaseControllerMixin
|
38
|
+
@extra_actions = {test: [:get]}
|
39
|
+
|
40
|
+
def test
|
41
|
+
render inline: "Test successful!"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
```
|
45
|
+
|
46
|
+
`ModelControllerMixin` assists with providing the standard CRUD for your controller.
|
47
|
+
|
48
|
+
```
|
49
|
+
class Api::MoviesController < ApiController
|
50
|
+
include RESTFramework::ModelControllerMixin
|
51
|
+
|
52
|
+
@recordset = Movie.where(enabled: true) # by default, @recordset would include all movies
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
`ReadOnlyModelControllerMixin` only enables list/show actions, but since we're naming this
|
57
|
+
controller in a way that doesn't make the model obvious, we can set that explicitly:
|
58
|
+
|
59
|
+
```
|
60
|
+
class Api::ReadOnlyMoviesController < ApiController
|
61
|
+
include RESTFramework::ReadOnlyModelControllerMixin
|
62
|
+
|
63
|
+
@model = Movie
|
64
|
+
end
|
65
|
+
```
|
66
|
+
|
67
|
+
Note that you can also override `get_model` and `get_recordset` instance methods to override the API
|
68
|
+
behavior based on each request.
|
69
|
+
|
70
|
+
### Routing
|
71
|
+
|
72
|
+
You can use Rails' `resource`/`resources` routers to route your API, however if you want
|
73
|
+
`@extra_actions`/`@extra_member_actions` to be routed automatically, then you can use the
|
74
|
+
`rest_resource`/`rest_resources` routers provided by this gem. You can also use `rest_root` to route
|
75
|
+
the root of your API:
|
76
|
+
|
77
|
+
```
|
78
|
+
Rails.application.routes.draw do
|
79
|
+
rest_root :api # will find `api_controller` and route the `root` action to '/api'
|
80
|
+
namespace :api do
|
81
|
+
rest_resources :movies
|
82
|
+
rest_resources :read_only_movies
|
83
|
+
end
|
84
|
+
end
|
85
|
+
```
|
86
|
+
|
87
|
+
Or if you want the API root to be routed to `Api::RootController#root`:
|
88
|
+
|
89
|
+
```
|
90
|
+
Rails.application.routes.draw do
|
91
|
+
namespace :api do
|
92
|
+
rest_root # will route `Api::RootController#root` to '/' in this namespace ('/api')
|
93
|
+
rest_resources :movies
|
94
|
+
rest_resources :read_only_movies
|
95
|
+
end
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
27
99
|
## Development/Testing
|
28
100
|
|
29
101
|
After you clone the repository, cd'ing into the directory should create a new gemset if you are
|
@@ -37,10 +109,10 @@ To run unit tests:
|
|
37
109
|
|
38
110
|
$ rake test:unit
|
39
111
|
|
40
|
-
To run integration tests
|
41
|
-
|
42
|
-
$ rake test:app
|
112
|
+
To run integration tests:
|
43
113
|
|
44
|
-
|
114
|
+
$ rake test:integration
|
45
115
|
|
46
|
-
|
116
|
+
To interact with the integration app, you can `cd test/integration` and operate it via the normal
|
117
|
+
Rails interfaces. Ensure you run `rake db:schema:load` before running `rails server` or
|
118
|
+
`rails console`.
|
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.1
|
@@ -1,6 +1,9 @@
|
|
1
1
|
module RESTFramework
|
2
2
|
|
3
|
+
# This module provides helpers for mixin `ClassMethods` submodules.
|
3
4
|
module ClassMethodHelpers
|
5
|
+
|
6
|
+
# This helper assists in providing reader interfaces for mixin properties.
|
4
7
|
def _restframework_attr_reader(property, default: nil)
|
5
8
|
method = <<~RUBY
|
6
9
|
def #{property}
|
@@ -14,6 +17,9 @@ module RESTFramework
|
|
14
17
|
end
|
15
18
|
end
|
16
19
|
|
20
|
+
# This module provides the common functionality for any controller mixins, a `root` action, and
|
21
|
+
# the ability to route arbitrary actions with `@extra_actions`. This is also where `api_response`
|
22
|
+
# is defined.
|
17
23
|
module BaseControllerMixin
|
18
24
|
# Default action for API root.
|
19
25
|
# TODO: use api_response and show sub-routes.
|
@@ -47,7 +53,20 @@ module RESTFramework
|
|
47
53
|
# end
|
48
54
|
|
49
55
|
_restframework_attr_reader(:extra_actions, default: {})
|
50
|
-
|
56
|
+
|
57
|
+
def skip_actions(skip_undefined: true)
|
58
|
+
# first, skip explicitly skipped actions
|
59
|
+
skip = _restframework_try_class_level_variable_get(:skip_actions, default: [])
|
60
|
+
|
61
|
+
# now add methods which don't exist, since we don't want to route those
|
62
|
+
if skip_undefined
|
63
|
+
[:index, :new, :create, :show, :edit, :update, :destroy].each do |a|
|
64
|
+
skip << a unless self.method_defined?(a)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
return skip
|
69
|
+
end
|
51
70
|
end
|
52
71
|
|
53
72
|
def self.included(base)
|
@@ -32,11 +32,14 @@ module RESTFramework
|
|
32
32
|
_restframework_attr_reader(:extra_member_actions, default: {})
|
33
33
|
|
34
34
|
# For model-based mixins, `@extra_collection_actions` is synonymous with `@extra_actions`.
|
35
|
-
|
36
|
-
|
35
|
+
# @param skip_undefined [Boolean] whether we should skip routing undefined actions
|
36
|
+
def extra_actions(skip_undefined: true)
|
37
|
+
actions = (
|
37
38
|
_restframework_try_class_level_variable_get(:extra_collection_actions) ||
|
38
39
|
_restframework_try_class_level_variable_get(:extra_actions, default: {})
|
39
40
|
)
|
41
|
+
actions = actions.select { |a| self.method_defined?(a) } if skip_undefined
|
42
|
+
return actions
|
40
43
|
end
|
41
44
|
end
|
42
45
|
|
@@ -109,10 +112,10 @@ module RESTFramework
|
|
109
112
|
end
|
110
113
|
|
111
114
|
# Internal interface for get_model, protecting against infinite recursion with get_recordset.
|
112
|
-
|
115
|
+
def _get_model(from_internal_get_recordset: false)
|
113
116
|
return @model if @model
|
114
117
|
return self.class.model if self.class.model
|
115
|
-
unless
|
118
|
+
unless from_internal_get_recordset # prevent infinite recursion
|
116
119
|
recordset = self._get_recordset(from_internal_get_model: true)
|
117
120
|
return (@model = recordset.klass) if recordset
|
118
121
|
end
|
@@ -124,10 +127,10 @@ module RESTFramework
|
|
124
127
|
end
|
125
128
|
|
126
129
|
# Internal interface for get_recordset, protecting against infinite recursion with get_model.
|
127
|
-
|
130
|
+
def _get_recordset(from_internal_get_model: false)
|
128
131
|
return @recordset if @recordset
|
129
132
|
return self.class.recordset if self.class.recordset
|
130
|
-
unless
|
133
|
+
unless from_internal_get_model # prevent infinite recursion
|
131
134
|
model = self._get_model(from_internal_get_recordset: true)
|
132
135
|
return (@recordset = model.all) if model
|
133
136
|
end
|
@@ -41,7 +41,8 @@ module ActionDispatch::Routing
|
|
41
41
|
# @param default_singular [Boolean] the default plurality of the resource if the plurality is
|
42
42
|
# not otherwise defined by the controller
|
43
43
|
# @param name [Symbol] the resource name, from which path and controller are deduced by default
|
44
|
-
|
44
|
+
# @param skip_undefined [Boolean] whether we should skip routing undefined actions
|
45
|
+
protected def _rest_resources(default_singular, name, skip_undefined: true, **kwargs, &block)
|
45
46
|
controller = kwargs[:controller] || name
|
46
47
|
if controller.is_a?(Class)
|
47
48
|
controller_class = controller
|
@@ -50,9 +51,7 @@ module ActionDispatch::Routing
|
|
50
51
|
end
|
51
52
|
|
52
53
|
# set controller if it's not explicitly set
|
53
|
-
unless kwargs[:controller]
|
54
|
-
kwargs[:controller] = name
|
55
|
-
end
|
54
|
+
kwargs[:controller] = name unless kwargs[:controller]
|
56
55
|
|
57
56
|
# determine plural/singular resource
|
58
57
|
if kwargs.delete(:force_singular)
|
@@ -67,10 +66,14 @@ module ActionDispatch::Routing
|
|
67
66
|
resource_method = singular ? :resource : :resources
|
68
67
|
|
69
68
|
# call either `resource` or `resources`, passing appropriate modifiers
|
70
|
-
|
69
|
+
skip_undefined = kwargs.delete(:skip_undefined) || true
|
70
|
+
skip = controller_class.skip_actions(skip_undefined: skip_undefined)
|
71
|
+
public_send(resource_method, name, except: skip, **kwargs) do
|
71
72
|
if controller_class.respond_to?(:extra_member_actions)
|
72
73
|
member do
|
73
|
-
controller_class.extra_member_actions
|
74
|
+
actions = controller_class.extra_member_actions
|
75
|
+
actions = actions.select { |k,v| controller_class.method_defined?(k) } if skip_undefined
|
76
|
+
actions.each do |action, methods|
|
74
77
|
methods = [methods] if methods.is_a?(Symbol) || methods.is_a?(String)
|
75
78
|
methods.each do |m|
|
76
79
|
public_send(m, action)
|
@@ -80,7 +83,9 @@ module ActionDispatch::Routing
|
|
80
83
|
end
|
81
84
|
|
82
85
|
collection do
|
83
|
-
controller_class.extra_actions
|
86
|
+
actions = controller_class.extra_actions
|
87
|
+
actions = actions.select { |k,v| controller_class.method_defined?(k) } if skip_undefined
|
88
|
+
actions.each do |action, methods|
|
84
89
|
methods = [methods] if methods.is_a?(Symbol) || methods.is_a?(String)
|
85
90
|
methods.each do |m|
|
86
91
|
public_send(m, action)
|
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.0.
|
4
|
+
version: 0.0.1
|
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: 2020-09-
|
11
|
+
date: 2020-09-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|