rest_framework 0.0.0 → 0.0.6
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 +4 -4
- data/README.md +80 -5
- data/app/views/layouts/rest_framework.html.erb +38 -0
- data/app/views/rest_framework/_head.html.erb +19 -0
- data/app/views/rest_framework/_routes.html.erb +18 -0
- data/app/views/rest_framework/default.html.erb +0 -0
- data/lib/rest_framework.rb +1 -0
- data/lib/rest_framework/VERSION_STAMP +1 -1
- data/lib/rest_framework/controllers/base.rb +73 -18
- data/lib/rest_framework/controllers/models.rb +17 -16
- data/lib/rest_framework/engine.rb +2 -0
- data/lib/rest_framework/routers.rb +14 -9
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3e577365f00c98803ebf7f4548c10e5e0cde9208d47de71ac5d5193d0e0c776
|
4
|
+
data.tar.gz: b0527bc192535edcd85a91587e11df09c30dff460701c826fe6574ec487bc003
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 805f9fe5d4fcd15f5e360459af7246e52392115f3cf6ab3fe51a2128f16c4092e10ac0797767769992416818cdf5dc429790e128ad7a889119cdb134d739ea61
|
7
|
+
data.tar.gz: d0079b9e2cb005938d95aa83cccc3971849183be3209e2c08a2ebae5c357d6c9c571663cd496f68c4a5f8855ea2b804a46fbfcb73d839693b41ce781563599c0
|
data/README.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# REST Framework
|
2
2
|
|
3
|
+
[](https://badge.fury.io/rb/rest_framework)
|
4
|
+
[](https://travis-ci.org/gregschmit/rails-rest-framework)
|
5
|
+
|
3
6
|
REST Framework helps you build awesome APIs in Ruby on Rails.
|
4
7
|
|
5
8
|
**The Problem**: Building controllers for APIs usually involves writing a lot of redundant CRUD
|
@@ -24,6 +27,78 @@ Or install it yourself with:
|
|
24
27
|
|
25
28
|
$ gem install rest_framework
|
26
29
|
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
### Controller Mixins
|
33
|
+
|
34
|
+
To transform a controller into a RESTful controller, you can either include `BaseControllerMixin`,
|
35
|
+
`ReadOnlyModelControllerMixin`, or `ModelControllerMixin`. `BaseControllerMixin` provides a `root`
|
36
|
+
action and a simple interface for routing arbitrary additional actions:
|
37
|
+
|
38
|
+
```
|
39
|
+
class ApiController < ApplicationController
|
40
|
+
include RESTFramework::BaseControllerMixin
|
41
|
+
@extra_actions = {test: [:get]}
|
42
|
+
|
43
|
+
def test
|
44
|
+
render inline: "Test successful!"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
`ModelControllerMixin` assists with providing the standard CRUD for your controller.
|
50
|
+
|
51
|
+
```
|
52
|
+
class Api::MoviesController < ApiController
|
53
|
+
include RESTFramework::ModelControllerMixin
|
54
|
+
|
55
|
+
@recordset = Movie.where(enabled: true) # by default, @recordset would include all movies
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
59
|
+
`ReadOnlyModelControllerMixin` only enables list/show actions, but since we're naming this
|
60
|
+
controller in a way that doesn't make the model obvious, we can set that explicitly:
|
61
|
+
|
62
|
+
```
|
63
|
+
class Api::ReadOnlyMoviesController < ApiController
|
64
|
+
include RESTFramework::ReadOnlyModelControllerMixin
|
65
|
+
|
66
|
+
@model = Movie
|
67
|
+
end
|
68
|
+
```
|
69
|
+
|
70
|
+
Note that you can also override `get_model` and `get_recordset` instance methods to override the API
|
71
|
+
behavior dynamically per-request.
|
72
|
+
|
73
|
+
### Routing
|
74
|
+
|
75
|
+
You can use Rails' `resource`/`resources` routers to route your API, however if you want
|
76
|
+
`@extra_actions` / `@extra_member_actions` to be routed automatically, then you can use the
|
77
|
+
`rest_resource` / `rest_resources` routers provided by this gem. You can also use `rest_root` to route
|
78
|
+
the root of your API:
|
79
|
+
|
80
|
+
```
|
81
|
+
Rails.application.routes.draw do
|
82
|
+
rest_root :api # will find `api_controller` and route the `root` action to '/api'
|
83
|
+
namespace :api do
|
84
|
+
rest_resources :movies
|
85
|
+
rest_resources :read_only_movies
|
86
|
+
end
|
87
|
+
end
|
88
|
+
```
|
89
|
+
|
90
|
+
Or if you want the API root to be routed to `Api::RootController#root`:
|
91
|
+
|
92
|
+
```
|
93
|
+
Rails.application.routes.draw do
|
94
|
+
namespace :api do
|
95
|
+
rest_root # will route `Api::RootController#root` to '/' in this namespace ('/api')
|
96
|
+
rest_resources :movies
|
97
|
+
rest_resources :read_only_movies
|
98
|
+
end
|
99
|
+
end
|
100
|
+
```
|
101
|
+
|
27
102
|
## Development/Testing
|
28
103
|
|
29
104
|
After you clone the repository, cd'ing into the directory should create a new gemset if you are
|
@@ -37,10 +112,10 @@ To run unit tests:
|
|
37
112
|
|
38
113
|
$ rake test:unit
|
39
114
|
|
40
|
-
To run integration tests
|
41
|
-
|
42
|
-
$ rake test:app
|
115
|
+
To run integration tests:
|
43
116
|
|
44
|
-
|
117
|
+
$ rake test:integration
|
45
118
|
|
46
|
-
|
119
|
+
To interact with the integration app, you can `cd test/integration` and operate it via the normal
|
120
|
+
Rails interfaces. Ensure you run `rake db:schema:load` before running `rails server` or
|
121
|
+
`rails console`.
|
@@ -0,0 +1,38 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title><%= @title %></title>
|
5
|
+
<%= render partial: 'rest_framework/head' %>
|
6
|
+
</head>
|
7
|
+
|
8
|
+
<body>
|
9
|
+
<div class="bg-dark">
|
10
|
+
<div class="w-100 m-0 p-0" style="height: .3em; background-color: #a00;"></div>
|
11
|
+
<nav class="navbar navbar-dark bg-dark">
|
12
|
+
<div class="container">
|
13
|
+
<span class="navbar-brand p-0">
|
14
|
+
<h1 class="text-light font-weight-light m-0 p-0" style="font-size: 1em"><%= @template_logo_text %></h1>
|
15
|
+
</span>
|
16
|
+
</div>
|
17
|
+
</nav>
|
18
|
+
</div>
|
19
|
+
<div class="container py-3">
|
20
|
+
<div class="container">
|
21
|
+
<div class="row">
|
22
|
+
<h1><%= @title %></h1>
|
23
|
+
</div>
|
24
|
+
<hr/>
|
25
|
+
<div class="row">
|
26
|
+
<h2>Payload</h2><br>
|
27
|
+
<div><pre><%= JSON.pretty_generate(JSON.parse(@serialized_payload)) %></pre></div>
|
28
|
+
</div>
|
29
|
+
<% unless @routes.blank? %>
|
30
|
+
<div class="row">
|
31
|
+
<h2>Routes</h2>
|
32
|
+
<%= render partial: 'rest_framework/routes' %>
|
33
|
+
</div>
|
34
|
+
<% end %>
|
35
|
+
</div>
|
36
|
+
</div>
|
37
|
+
</body>
|
38
|
+
</html>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<meta charset="utf-8">
|
2
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
3
|
+
<%= csrf_meta_tags %>
|
4
|
+
<%= csp_meta_tag rescue nil %>
|
5
|
+
|
6
|
+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
|
7
|
+
<style>
|
8
|
+
h1,h2,h3,h4,h5,h6 { width: 100%; }
|
9
|
+
h1 { font-size: 2rem; }
|
10
|
+
h2 { font-size: 1.7rem; }
|
11
|
+
h3 { font-size: 1.5rem; }
|
12
|
+
h4 { font-size: 1.3rem; }
|
13
|
+
h5 { font-size: 1.1rem; }
|
14
|
+
h6 { font-size: 1rem; }
|
15
|
+
</style>
|
16
|
+
|
17
|
+
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
|
18
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
|
19
|
+
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<table class="table">
|
2
|
+
<thead>
|
3
|
+
<tr>
|
4
|
+
<th scope="col">Verb</th>
|
5
|
+
<th scope="col">Path</th>
|
6
|
+
<th scope="col">Action</th>
|
7
|
+
</tr>
|
8
|
+
</thead>
|
9
|
+
<tbody>
|
10
|
+
<% @routes.each do |r| %>
|
11
|
+
<tr>
|
12
|
+
<td><%= r[:verb] %></td>
|
13
|
+
<td><%= r[:path] %></td>
|
14
|
+
<td><%= r[:action] %></td>
|
15
|
+
</tr>
|
16
|
+
<% end %>
|
17
|
+
</tbody>
|
18
|
+
</table>
|
File without changes
|
data/lib/rest_framework.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.6
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module RESTFramework
|
2
2
|
|
3
|
+
# This module provides helpers for mixin `ClassMethods` submodules.
|
3
4
|
module ClassMethodHelpers
|
5
|
+
# This helper assists in providing reader interfaces for mixin properties.
|
4
6
|
def _restframework_attr_reader(property, default: nil)
|
5
7
|
method = <<~RUBY
|
6
8
|
def #{property}
|
@@ -14,11 +16,13 @@ module RESTFramework
|
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
19
|
+
# This module provides the common functionality for any controller mixins, a `root` action, and
|
20
|
+
# the ability to route arbitrary actions with `@extra_actions`. This is also where `api_response`
|
21
|
+
# is defined.
|
17
22
|
module BaseControllerMixin
|
18
23
|
# Default action for API root.
|
19
|
-
# TODO: use api_response and show sub-routes.
|
20
24
|
def root
|
21
|
-
|
25
|
+
api_response({message: "This is the root of your awesome API!"})
|
22
26
|
end
|
23
27
|
|
24
28
|
protected
|
@@ -26,39 +30,90 @@ module RESTFramework
|
|
26
30
|
module ClassMethods
|
27
31
|
extend ClassMethodHelpers
|
28
32
|
|
29
|
-
# Interface for getting class-level instance/class variables.
|
33
|
+
# Interface for getting class-level instance/class variables. Note: we check if they are
|
34
|
+
# defined first rather than rescuing NameError to prevent uninitialized variable warnings.
|
30
35
|
private def _restframework_try_class_level_variable_get(name, default: nil)
|
31
|
-
|
32
|
-
|
36
|
+
instance_variable = "@#{name}"
|
37
|
+
if self.instance_variable_defined?(instance_variable)
|
38
|
+
v = self.instance_variable_get(instance_variable)
|
33
39
|
return v unless v.nil?
|
34
|
-
rescue NameError
|
35
40
|
end
|
36
|
-
|
37
|
-
|
41
|
+
class_variable = "@@#{name}"
|
42
|
+
if self.class_variable_defined?(class_variable)
|
43
|
+
v = self.class_variable_get(class_variable)
|
38
44
|
return v unless v.nil?
|
39
|
-
rescue NameError
|
40
45
|
end
|
41
46
|
return default
|
42
47
|
end
|
43
48
|
|
44
|
-
|
45
|
-
# private def _restframework_register_exception_handlers
|
46
|
-
# rescue_from
|
47
|
-
# end
|
48
|
-
|
49
|
+
_restframework_attr_reader(:singleton_controller)
|
49
50
|
_restframework_attr_reader(:extra_actions, default: {})
|
50
|
-
_restframework_attr_reader(:
|
51
|
+
_restframework_attr_reader(:template_logo_text, default: 'Rails REST Framework')
|
52
|
+
|
53
|
+
def skip_actions(skip_undefined: true)
|
54
|
+
# first, skip explicitly skipped actions
|
55
|
+
skip = _restframework_try_class_level_variable_get(:skip_actions, default: [])
|
56
|
+
|
57
|
+
# now add methods which don't exist, since we don't want to route those
|
58
|
+
if skip_undefined
|
59
|
+
[:index, :new, :create, :show, :edit, :update, :destroy].each do |a|
|
60
|
+
skip << a unless self.method_defined?(a)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
return skip
|
65
|
+
end
|
51
66
|
end
|
52
67
|
|
53
68
|
def self.included(base)
|
54
69
|
base.extend ClassMethods
|
55
70
|
end
|
56
71
|
|
72
|
+
def _get_routes
|
73
|
+
begin
|
74
|
+
formatter = ActionDispatch::Routing::ConsoleFormatter::Sheet
|
75
|
+
rescue NameError
|
76
|
+
formatter = ActionDispatch::Routing::ConsoleFormatter
|
77
|
+
end
|
78
|
+
return ActionDispatch::Routing::RoutesInspector.new(Rails.application.routes.routes).format(
|
79
|
+
formatter.new
|
80
|
+
).lines[1..].map { |r| r.split.last(3) }.map { |r|
|
81
|
+
{verb: r[0], path: r[1], action: r[2]}
|
82
|
+
}.select { |r| r[:path].start_with?(request.path) }
|
83
|
+
end
|
84
|
+
|
57
85
|
# Helper alias for `respond_to`/`render`, and replace nil responses with blank ones.
|
58
|
-
def api_response(
|
86
|
+
def api_response(payload, html_kwargs: nil, json_kwargs: nil, **kwargs)
|
87
|
+
payload ||= '' # replace nil with ''
|
88
|
+
html_kwargs ||= {}
|
89
|
+
json_kwargs ||= {}
|
90
|
+
|
91
|
+
# serialize
|
92
|
+
if self.respond_to?(:get_model_serializer_config, true)
|
93
|
+
serialized_payload = payload.to_json(self.get_model_serializer_config)
|
94
|
+
else
|
95
|
+
serialized_payload = payload.to_json
|
96
|
+
end
|
97
|
+
|
59
98
|
respond_to do |format|
|
60
|
-
format.html
|
61
|
-
|
99
|
+
format.html {
|
100
|
+
kwargs = kwargs.merge(html_kwargs)
|
101
|
+
@template_logo_text ||= self.class.template_logo_text
|
102
|
+
@title ||= self.controller_name.camelize
|
103
|
+
@routes ||= self._get_routes
|
104
|
+
@payload = payload
|
105
|
+
@serialized_payload = serialized_payload
|
106
|
+
begin
|
107
|
+
render(**kwargs)
|
108
|
+
rescue ActionView::MissingTemplate # fallback to rest_framework default view
|
109
|
+
kwargs[:template] = "rest_framework/default"
|
110
|
+
end
|
111
|
+
render(**kwargs)
|
112
|
+
}
|
113
|
+
format.json {
|
114
|
+
kwargs = kwargs.merge(json_kwargs)
|
115
|
+
render(json: serialized_payload || '', **kwargs)
|
116
|
+
}
|
62
117
|
end
|
63
118
|
end
|
64
119
|
end
|
@@ -21,7 +21,6 @@ module RESTFramework
|
|
21
21
|
|
22
22
|
_restframework_attr_reader(:model)
|
23
23
|
_restframework_attr_reader(:recordset)
|
24
|
-
_restframework_attr_reader(:singleton_controller)
|
25
24
|
|
26
25
|
_restframework_attr_reader(:fields)
|
27
26
|
_restframework_attr_reader(:list_fields)
|
@@ -32,11 +31,14 @@ module RESTFramework
|
|
32
31
|
_restframework_attr_reader(:extra_member_actions, default: {})
|
33
32
|
|
34
33
|
# For model-based mixins, `@extra_collection_actions` is synonymous with `@extra_actions`.
|
35
|
-
|
36
|
-
|
34
|
+
# @param skip_undefined [Boolean] whether we should skip routing undefined actions
|
35
|
+
def extra_actions(skip_undefined: true)
|
36
|
+
actions = (
|
37
37
|
_restframework_try_class_level_variable_get(:extra_collection_actions) ||
|
38
38
|
_restframework_try_class_level_variable_get(:extra_actions, default: {})
|
39
39
|
)
|
40
|
+
actions = actions.select { |a| self.method_defined?(a) } if skip_undefined
|
41
|
+
return actions
|
40
42
|
end
|
41
43
|
end
|
42
44
|
|
@@ -48,7 +50,7 @@ module RESTFramework
|
|
48
50
|
|
49
51
|
# Get a list of fields for the current action.
|
50
52
|
def get_fields
|
51
|
-
return @fields if @fields
|
53
|
+
return @fields if instance_variable_defined?(:@fields) && @fields
|
52
54
|
|
53
55
|
# index action should use list_fields
|
54
56
|
name = (action_name == 'index') ? 'list' : action_name
|
@@ -57,9 +59,8 @@ module RESTFramework
|
|
57
59
|
@fields = self.class.send("#{name}_fields")
|
58
60
|
rescue NameError
|
59
61
|
end
|
60
|
-
@fields ||= self.class.fields || []
|
61
62
|
|
62
|
-
return @fields
|
63
|
+
return @fields ||= self.class.fields || []
|
63
64
|
end
|
64
65
|
|
65
66
|
# Get a configuration passable to `as_json` for the model.
|
@@ -109,10 +110,10 @@ module RESTFramework
|
|
109
110
|
end
|
110
111
|
|
111
112
|
# Internal interface for get_model, protecting against infinite recursion with get_recordset.
|
112
|
-
|
113
|
-
return @model if @model
|
113
|
+
def _get_model(from_internal_get_recordset: false)
|
114
|
+
return @model if instance_variable_defined?(:@model) && @model
|
114
115
|
return self.class.model if self.class.model
|
115
|
-
unless
|
116
|
+
unless from_internal_get_recordset # prevent infinite recursion
|
116
117
|
recordset = self._get_recordset(from_internal_get_model: true)
|
117
118
|
return (@model = recordset.klass) if recordset
|
118
119
|
end
|
@@ -124,10 +125,10 @@ module RESTFramework
|
|
124
125
|
end
|
125
126
|
|
126
127
|
# Internal interface for get_recordset, protecting against infinite recursion with get_model.
|
127
|
-
|
128
|
-
return @recordset if @recordset
|
128
|
+
def _get_recordset(from_internal_get_model: false)
|
129
|
+
return @recordset if instance_variable_defined?(:@recordset) && @recordset
|
129
130
|
return self.class.recordset if self.class.recordset
|
130
|
-
unless
|
131
|
+
unless from_internal_get_model # prevent infinite recursion
|
131
132
|
model = self._get_model(from_internal_get_recordset: true)
|
132
133
|
return (@recordset = model.all) if model
|
133
134
|
end
|
@@ -149,14 +150,14 @@ module RESTFramework
|
|
149
150
|
# TODO: pagination classes like Django
|
150
151
|
def index
|
151
152
|
@records = self.get_filtered_recordset
|
152
|
-
api_response(@records
|
153
|
+
api_response(@records)
|
153
154
|
end
|
154
155
|
end
|
155
156
|
|
156
157
|
module ShowModelMixin
|
157
158
|
def show
|
158
159
|
@record = self.get_record
|
159
|
-
api_response(@record
|
160
|
+
api_response(@record)
|
160
161
|
end
|
161
162
|
end
|
162
163
|
|
@@ -167,7 +168,7 @@ module RESTFramework
|
|
167
168
|
rescue ActiveRecord::RecordInvalid => e
|
168
169
|
api_response(e.record.messages, status: 400)
|
169
170
|
end
|
170
|
-
api_response(@record
|
171
|
+
api_response(@record)
|
171
172
|
end
|
172
173
|
end
|
173
174
|
|
@@ -177,7 +178,7 @@ module RESTFramework
|
|
177
178
|
if @record
|
178
179
|
@record.attributes(self.get_update_params)
|
179
180
|
@record.save!
|
180
|
-
api_response(@record
|
181
|
+
api_response(@record)
|
181
182
|
else
|
182
183
|
api_response({detail: "Record not found."}, status: 404)
|
183
184
|
end
|
@@ -25,10 +25,10 @@ module ActionDispatch::Routing
|
|
25
25
|
|
26
26
|
# convert class name to class
|
27
27
|
begin
|
28
|
-
controller = mod.const_get(name
|
28
|
+
controller = mod.const_get(name)
|
29
29
|
rescue NameError
|
30
30
|
if fallback_reverse_pluralization
|
31
|
-
controller = mod.const_get(name_reverse
|
31
|
+
controller = mod.const_get(name_reverse)
|
32
32
|
else
|
33
33
|
raise
|
34
34
|
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.6
|
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-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -33,11 +33,16 @@ extra_rdoc_files: []
|
|
33
33
|
files:
|
34
34
|
- LICENSE
|
35
35
|
- README.md
|
36
|
+
- app/views/layouts/rest_framework.html.erb
|
37
|
+
- app/views/rest_framework/_head.html.erb
|
38
|
+
- app/views/rest_framework/_routes.html.erb
|
39
|
+
- app/views/rest_framework/default.html.erb
|
36
40
|
- lib/rest_framework.rb
|
37
41
|
- lib/rest_framework/VERSION_STAMP
|
38
42
|
- lib/rest_framework/controllers.rb
|
39
43
|
- lib/rest_framework/controllers/base.rb
|
40
44
|
- lib/rest_framework/controllers/models.rb
|
45
|
+
- lib/rest_framework/engine.rb
|
41
46
|
- lib/rest_framework/routers.rb
|
42
47
|
- lib/rest_framework/version.rb
|
43
48
|
homepage: https://github.com/gregschmit/rails-rest-framework
|
@@ -50,6 +55,7 @@ post_install_message:
|
|
50
55
|
rdoc_options: []
|
51
56
|
require_paths:
|
52
57
|
- lib
|
58
|
+
- app
|
53
59
|
required_ruby_version: !ruby/object:Gem::Requirement
|
54
60
|
requirements:
|
55
61
|
- - ">="
|