rest_framework 0.9.4 → 0.9.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/README.md +130 -0
- data/VERSION +1 -1
- data/app/views/layouts/rest_framework.html.erb +9 -183
- data/app/views/rest_framework/_breadcrumbs.html.erb +27 -0
- data/app/views/rest_framework/_head.html.erb +348 -190
- data/app/views/rest_framework/_header.html.erb +15 -0
- data/app/views/rest_framework/_heading.html.erb +10 -0
- data/app/views/rest_framework/_payloads.html.erb +36 -0
- data/app/views/rest_framework/_request_metadata.html.erb +16 -0
- data/app/views/rest_framework/_routes_and_forms.html.erb +52 -0
- data/app/views/rest_framework/head/_external.html.erb +7 -2
- data/app/views/rest_framework/header/_mode.html.erb +14 -0
- data/app/views/rest_framework/heading/_actions.html.erb +9 -0
- data/app/views/rest_framework/{_routes.html.erb → routes_and_forms/_routes.html.erb} +2 -2
- data/lib/rest_framework/controller_mixins/base.rb +11 -12
- data/lib/rest_framework/engine.rb +5 -3
- data/lib/rest_framework/filters/ransack.rb +6 -6
- data/lib/rest_framework/version.rb +0 -6
- data/lib/rest_framework.rb +25 -13
- data/vendor/assets/javascripts/rest_framework/external.min.js +1256 -0
- data/vendor/assets/stylesheets/rest_framework/{bootstrap-icons.css → external.min.css} +415 -1
- data/vendor/assets/stylesheets/rest_framework/{highlight-a11y-dark.css → highlight-a11y-dark.min.css} +1 -1
- data/vendor/assets/stylesheets/rest_framework/{highlight-a11y-light.css → highlight-a11y-light.min.css} +1 -1
- metadata +18 -35
- data/README.md +0 -1
- data/app/views/rest_framework/head/_shared.html +0 -164
- data/docs/CNAME +0 -1
- data/docs/Gemfile +0 -5
- data/docs/Gemfile.lock +0 -264
- data/docs/_config.yml +0 -19
- data/docs/_guide/1_routers.md +0 -110
- data/docs/_guide/2_controllers.md +0 -342
- data/docs/_guide/3_serializers.md +0 -60
- data/docs/_guide/4_filtering_and_ordering.md +0 -41
- data/docs/_guide/5_pagination.md +0 -21
- data/docs/_includes/anchor_headings.html +0 -144
- data/docs/_includes/external.html +0 -9
- data/docs/_includes/head.html +0 -155
- data/docs/_includes/header.html +0 -58
- data/docs/_includes/shared.html +0 -164
- data/docs/_layouts/default.html +0 -11
- data/docs/assets/images/favicon.ico +0 -0
- data/docs/index.md +0 -133
- data/vendor/assets/javascripts/rest_framework/bootstrap.js +0 -7
- data/vendor/assets/javascripts/rest_framework/highlight-json.js +0 -7
- data/vendor/assets/javascripts/rest_framework/highlight-xml.js +0 -29
- data/vendor/assets/javascripts/rest_framework/highlight.js +0 -1202
- data/vendor/assets/javascripts/rest_framework/neatjson.js +0 -8
- data/vendor/assets/javascripts/rest_framework/trix.js +0 -6
- data/vendor/assets/stylesheets/rest_framework/bootstrap.css +0 -6
- data/vendor/assets/stylesheets/rest_framework/trix.css +0 -410
- /data/app/views/rest_framework/{_html_form.html.erb → routes_and_forms/_html_form.html.erb} +0 -0
- /data/app/views/rest_framework/{_raw_form.html.erb → routes_and_forms/_raw_form.html.erb} +0 -0
- /data/app/views/rest_framework/{_route.html.erb → routes_and_forms/routes/_route.html.erb} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c26bdb290be334d911d6270e010568d3674f12a3e63dfa0f51337b242907317c
|
4
|
+
data.tar.gz: '07897cd01fe0f3df22af8d8466b49835d8e1db623b8e6066b407675989e0b9b2'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 71952c62c0f9165d837afbec82168ce11361c6e9655d4c73beabfe0e7de40f18c6cb059a7b76b5bf5fe38a5f6c3b545f8df7c5b60724900cf1d1d32a5b3cb8e8
|
7
|
+
data.tar.gz: 74ed89e118d69516d0bdd6a5cdcfa99e125fa80c45a48af2c99b8c79744041519c3e316a4f82c2737cdb41949a3bf9243c93b90090ab426880778d0b81fb1c61
|
data/LICENSE
CHANGED
data/README.md
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
# Rails REST Framework
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/rest_framework.svg)](https://badge.fury.io/rb/rest_framework)
|
4
|
+
[![Pipeline](https://github.com/gregschmit/rails-rest-framework/actions/workflows/pipeline.yml/badge.svg)](https://github.com/gregschmit/rails-rest-framework/actions/workflows/pipeline.yml)
|
5
|
+
[![Coverage](https://coveralls.io/repos/github/gregschmit/rails-rest-framework/badge.svg?branch=master)](https://coveralls.io/github/gregschmit/rails-rest-framework?branch=master)
|
6
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/ba5df7706cb544d78555/maintainability)](https://codeclimate.com/github/gregschmit/rails-rest-framework/maintainability)
|
7
|
+
|
8
|
+
A framework for DRY RESTful APIs in Ruby on Rails.
|
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.
|
13
|
+
|
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.
|
16
|
+
|
17
|
+
Website/Guide: [rails-rest-framework.com](https://rails-rest-framework.com)
|
18
|
+
|
19
|
+
Demo API: [rails-rest-framework.com/api/demo](https://rails-rest-framework.com/api/demo)
|
20
|
+
|
21
|
+
Source: [github.com/gregschmit/rails-rest-framework](https://github.com/gregschmit/rails-rest-framework)
|
22
|
+
|
23
|
+
YARD Docs: [rubydoc.info/gems/rest_framework](https://rubydoc.info/gems/rest_framework)
|
24
|
+
|
25
|
+
## Installation
|
26
|
+
|
27
|
+
Add this line to your application's Gemfile:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
gem 'rest_framework'
|
31
|
+
```
|
32
|
+
|
33
|
+
And then execute:
|
34
|
+
|
35
|
+
```shell
|
36
|
+
$ bundle install
|
37
|
+
```
|
38
|
+
|
39
|
+
Or install it yourself with:
|
40
|
+
|
41
|
+
```shell
|
42
|
+
$ gem install rest_framework
|
43
|
+
```
|
44
|
+
|
45
|
+
## Quick Usage Tutorial
|
46
|
+
|
47
|
+
### Controller Mixins
|
48
|
+
|
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:
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
class ApiController < ApplicationController
|
55
|
+
include RESTFramework::BaseControllerMixin
|
56
|
+
self.extra_actions = {test: :get}
|
57
|
+
|
58
|
+
def test
|
59
|
+
render api_response({message: "Test successful!"})
|
60
|
+
end
|
61
|
+
end
|
62
|
+
```
|
63
|
+
|
64
|
+
`ModelControllerMixin` assists with providing the standard model CRUD for your controller.
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
class Api::MoviesController < ApiController
|
68
|
+
include RESTFramework::ModelControllerMixin
|
69
|
+
|
70
|
+
self.recordset = Movie.where(enabled: true)
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
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:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
class Api::ReadOnlyMoviesController < ApiController
|
79
|
+
include RESTFramework::ReadOnlyModelControllerMixin
|
80
|
+
|
81
|
+
self.model = Movie
|
82
|
+
end
|
83
|
+
```
|
84
|
+
|
85
|
+
Note that you can also override the `get_recordset` instance method to override the API behavior
|
86
|
+
dynamically per-request.
|
87
|
+
|
88
|
+
### Routing
|
89
|
+
|
90
|
+
You can use Rails' `resource`/`resources` routers to route your API, however if you want
|
91
|
+
`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:
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
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`:
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
Rails.application.routes.draw do
|
109
|
+
namespace :api do
|
110
|
+
rest_root # will route `Api::RootController#root` to '/' in this namespace ('/api')
|
111
|
+
rest_resources :movies
|
112
|
+
rest_resources :users
|
113
|
+
end
|
114
|
+
end
|
115
|
+
```
|
116
|
+
|
117
|
+
## Development/Testing
|
118
|
+
|
119
|
+
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
|
+
```
|
127
|
+
|
128
|
+
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`.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.9.
|
1
|
+
0.9.6
|
@@ -8,195 +8,21 @@
|
|
8
8
|
<%= csp_meta_tag rescue nil %>
|
9
9
|
|
10
10
|
<%= render partial: "rest_framework/head", cached: true %>
|
11
|
+
|
12
|
+
<%= yield :head %>
|
11
13
|
</head>
|
12
14
|
|
13
15
|
<body>
|
14
16
|
<header>
|
15
|
-
|
16
|
-
<nav class="navbar py-0" data-bs-theme="dark">
|
17
|
-
<div class="container">
|
18
|
-
<span class="navbar-brand p-0">
|
19
|
-
<h1 title="RRF v<%= RESTFramework::VERSION %>" class="text-light font-weight-light m-0 p-0" style="font-size: 1em">
|
20
|
-
<%= @template_logo_text || "Rails REST Framework" %>
|
21
|
-
</h1>
|
22
|
-
</span>
|
23
|
-
<div class="dropdown ms-auto" id="rrfModeComponent">
|
24
|
-
<button class="btn btn-dark dropdown-toggle rounded-0 bg-black" style="border-color: black" data-bs-toggle="dropdown"></button>
|
25
|
-
<div class="rrf-mode dropdown-menu dropdown-menu-end py-0 rounded-0" style="font-size: .8em; min-width: 0">
|
26
|
-
<button class="dropdown-item text-end" data-rrf-mode-value="system">
|
27
|
-
System<i class="bi bi-circle-half ms-2"></i>
|
28
|
-
</button>
|
29
|
-
<button class="dropdown-item text-end" data-rrf-mode-value="light">
|
30
|
-
Light<i class="bi bi-sun-fill ms-2"></i>
|
31
|
-
</button>
|
32
|
-
<button class="dropdown-item text-end" data-rrf-mode-value="dark">
|
33
|
-
Dark<i class="bi bi-moon-stars-fill ms-2"></i>
|
34
|
-
</button>
|
35
|
-
</div>
|
36
|
-
</div>
|
37
|
-
</div>
|
38
|
-
</nav>
|
17
|
+
<%= render partial: "rest_framework/header" %>
|
39
18
|
</header>
|
40
19
|
<div class="container py-3">
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
next breadcrumbs if part.blank?
|
48
|
-
|
49
|
-
last_path = breadcrumbs.last&.first || "/"
|
50
|
-
breadcrumbs << [
|
51
|
-
[last_path, part].join(last_path[-1] == "/" ? "" : "/"),
|
52
|
-
part,
|
53
|
-
]
|
54
|
-
|
55
|
-
next breadcrumbs
|
56
|
-
}
|
57
|
-
%>
|
58
|
-
<% breadcrumbs.each_with_index do |(path, label), i| %>
|
59
|
-
<% if i != breadcrumbs.size - 1 %>
|
60
|
-
<li class="breadcrumb-item"><a href="<%= path %>"><%= label %></a></li>
|
61
|
-
<% else %>
|
62
|
-
<li class="breadcrumb-item active"><%= label %></li>
|
63
|
-
<% end %>
|
64
|
-
<% end %>
|
65
|
-
</ol>
|
66
|
-
</nav>
|
67
|
-
</div>
|
68
|
-
<div class="row">
|
69
|
-
<div>
|
70
|
-
<h1 class="m-0"><%= (@header_text if defined? @header_text) || @title %></h1>
|
71
|
-
<div style="float: right">
|
72
|
-
<% if @route_groups.values[0].any? { |r| r[:matches_path] && r[:verb] == "DELETE" && r[:action] == "destroy" } %>
|
73
|
-
<button type="button" class="btn btn-danger" onclick="rrfDelete(this)">DELETE</button>
|
74
|
-
<% end %>
|
75
|
-
<% if @route_groups.values[0].any? { |r| r[:matches_path] && r[:verb] == "OPTIONS" } %>
|
76
|
-
<button type="button" class="btn btn-primary" onclick="rrfOptions(this)">OPTIONS</button>
|
77
|
-
<% end %>
|
78
|
-
<button type="button" class="btn btn-primary" onclick="rrfGet(this)">GET</button>
|
79
|
-
</div>
|
80
|
-
<% if @description.present? %>
|
81
|
-
<br><br><p style="display: inline-block; margin-bottom: 0"><%= @description %></p>
|
82
|
-
<% end %>
|
83
|
-
</div>
|
84
|
-
</div>
|
85
|
-
<hr/>
|
86
|
-
<div class="row">
|
87
|
-
<div>
|
88
|
-
<pre style="white-space: normal">
|
89
|
-
<code>
|
90
|
-
<strong>
|
91
|
-
<%= request.request_method %>
|
92
|
-
<% if request.method != request.request_method %>
|
93
|
-
(via <%= request.method %>)
|
94
|
-
<% end %>
|
95
|
-
</strong> <%= request.path %><br>
|
96
|
-
</code>
|
97
|
-
</pre>
|
98
|
-
<pre style="white-space: normal">
|
99
|
-
<code>
|
100
|
-
<strong>HTTP <%= response.status %> <%= response.message %></strong><br>
|
101
|
-
<strong>Content-Type:</strong> <%= response.content_type %>
|
102
|
-
</code>
|
103
|
-
</pre>
|
104
|
-
</div>
|
105
|
-
</div>
|
106
|
-
<% if @json_payload.present? || @xml_payload.present? %>
|
107
|
-
<div class="row">
|
108
|
-
<div>
|
109
|
-
<ul class="nav nav-tabs">
|
110
|
-
<% if @json_payload.present? %>
|
111
|
-
<li class="nav-item">
|
112
|
-
<a class="nav-link active" href="#tab-json" data-bs-toggle="tab" role="tab">
|
113
|
-
.json
|
114
|
-
</a>
|
115
|
-
</li>
|
116
|
-
<% end %>
|
117
|
-
<% if @xml_payload.present? %>
|
118
|
-
<li class="nav-item">
|
119
|
-
<a class="nav-link" href="#tab-xml" data-bs-toggle="tab" role="tab">
|
120
|
-
.xml
|
121
|
-
</a>
|
122
|
-
</li>
|
123
|
-
<% end %>
|
124
|
-
</ul>
|
125
|
-
</div>
|
126
|
-
<div class="tab-content pt-2">
|
127
|
-
<div class="tab-pane fade show active" id="tab-json" role="tabpanel">
|
128
|
-
<% if @json_payload.present? %>
|
129
|
-
<div><pre class="rrf-copy"><code class="auto-hljs language-json"><%=
|
130
|
-
JSON.pretty_generate(
|
131
|
-
JSON.parse(@json_payload)
|
132
|
-
) unless @json_payload == ''
|
133
|
-
%></code></pre></div>
|
134
|
-
<% end %>
|
135
|
-
</div>
|
136
|
-
<div class="tab-pane fade" id="tab-xml" role="tabpanel">
|
137
|
-
<% if @xml_payload.present? %>
|
138
|
-
<div><pre class="rrf-copy"><code class="auto-hljs language-xml"><%=
|
139
|
-
CGI.unescapeHTML(@xml_payload)
|
140
|
-
%></code></pre></div>
|
141
|
-
<% end %>
|
142
|
-
</div>
|
143
|
-
</div>
|
144
|
-
</div>
|
145
|
-
<% end %>
|
146
|
-
<% if @route_groups.present? %>
|
147
|
-
<%
|
148
|
-
@is_model_controller = controller.class.included_modules.include?(RESTFramework::ModelControllerMixin)
|
149
|
-
%>
|
150
|
-
<div class="row">
|
151
|
-
<div>
|
152
|
-
<ul class="nav nav-tabs">
|
153
|
-
<li class="nav-item">
|
154
|
-
<a class="nav-link active" href="#tab-routes" data-bs-toggle="tab" role="tab">
|
155
|
-
Routes
|
156
|
-
</a>
|
157
|
-
</li>
|
158
|
-
<% @_rrf_form_routes_raw = @route_groups.values[0].select { |r|
|
159
|
-
r[:matches_params] && (
|
160
|
-
r[:verb].in?(["POST", "PUT", "PATCH"]) ||
|
161
|
-
(r[:verb] == "DELETE" && r[:action] == "destroy_all")
|
162
|
-
)
|
163
|
-
} %>
|
164
|
-
<% @_rrf_form_routes_html = @route_groups.values[0].select { |r|
|
165
|
-
r[:matches_params] && r[:verb].in?(["POST", "PUT", "PATCH"])
|
166
|
-
} %>
|
167
|
-
<% if @_rrf_form_routes_raw.present? %>
|
168
|
-
<li class="nav-item">
|
169
|
-
<a class="nav-link" href="#tabRawForm" data-bs-toggle="tab" role="tab">
|
170
|
-
Raw Form
|
171
|
-
</a>
|
172
|
-
</li>
|
173
|
-
<% end %>
|
174
|
-
<% if @_rrf_form_routes_html.present? && @is_model_controller %>
|
175
|
-
<li class="nav-item">
|
176
|
-
<a class="nav-link" href="#tabHtmlForm" data-bs-toggle="tab" role="tab">
|
177
|
-
HTML Form
|
178
|
-
</a>
|
179
|
-
</li>
|
180
|
-
<% end %>
|
181
|
-
</ul>
|
182
|
-
</div>
|
183
|
-
<div class="tab-content pt-2">
|
184
|
-
<div class="tab-pane fade show active" id="tab-routes" role="tabpanel">
|
185
|
-
<%= render partial: "rest_framework/routes" %>
|
186
|
-
</div>
|
187
|
-
<% if @_rrf_form_routes_raw.present? %>
|
188
|
-
<div class="tab-pane fade" id="tabRawForm" role="tabpanel">
|
189
|
-
<%= render partial: "rest_framework/raw_form" %>
|
190
|
-
</div>
|
191
|
-
<% end %>
|
192
|
-
<% if @_rrf_form_routes_html.present? && @is_model_controller %>
|
193
|
-
<div class="tab-pane fade" id="tabHtmlForm" role="tabpanel">
|
194
|
-
<%= render partial: "rest_framework/html_form" %>
|
195
|
-
</div>
|
196
|
-
<% end %>
|
197
|
-
</div>
|
198
|
-
</div>
|
199
|
-
<% end %>
|
20
|
+
<%= render partial: "rest_framework/breadcrumbs" unless @hide_breadcrumbs %>
|
21
|
+
<%= render partial: "rest_framework/heading" unless @hide_heading %>
|
22
|
+
<%= render partial: "rest_framework/request_metadata" unless @hide_request_metadata %>
|
23
|
+
<%= yield %>
|
24
|
+
<%= render partial: "rest_framework/payloads" if @json_payload.present? || @xml_payload.present? %>
|
25
|
+
<%= render partial: "rest_framework/routes_and_forms" if @route_groups.present? %>
|
200
26
|
</div>
|
201
27
|
</body>
|
202
28
|
</html>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<div class="row">
|
2
|
+
<nav>
|
3
|
+
<ol class="breadcrumb">
|
4
|
+
<%
|
5
|
+
breadcrumbs = request.path.split("/").inject([]) { |breadcrumbs, part|
|
6
|
+
# Ignore blank parts of the path (leading slash or double-slashes).
|
7
|
+
next breadcrumbs if part.blank?
|
8
|
+
|
9
|
+
last_path = breadcrumbs.last&.first || "/"
|
10
|
+
breadcrumbs << [
|
11
|
+
[last_path, part].join(last_path[-1] == "/" ? "" : "/"),
|
12
|
+
part,
|
13
|
+
]
|
14
|
+
|
15
|
+
next breadcrumbs
|
16
|
+
}
|
17
|
+
%>
|
18
|
+
<% breadcrumbs.each_with_index do |(path, label), i| %>
|
19
|
+
<% if i != breadcrumbs.size - 1 %>
|
20
|
+
<li class="breadcrumb-item"><a href="<%= path %>"><%= label %></a></li>
|
21
|
+
<% else %>
|
22
|
+
<li class="breadcrumb-item active"><%= label %></li>
|
23
|
+
<% end %>
|
24
|
+
<% end %>
|
25
|
+
</ol>
|
26
|
+
</nav>
|
27
|
+
</div>
|