rest_framework 0.8.16 → 0.9.0
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/VERSION +1 -1
- data/app/views/layouts/rest_framework.html.erb +149 -132
- data/app/views/rest_framework/_head.html.erb +204 -44
- data/app/views/rest_framework/_html_form.html.erb +1 -1
- data/docs/CNAME +1 -0
- data/docs/Gemfile +4 -0
- data/docs/Gemfile.lock +264 -0
- data/docs/_config.yml +17 -0
- data/docs/_guide/1_routers.md +110 -0
- data/docs/_guide/2_controller_mixins.md +293 -0
- data/docs/_guide/3_serializers.md +60 -0
- data/docs/_guide/4_filtering_and_ordering.md +41 -0
- data/docs/_guide/5_pagination.md +21 -0
- data/docs/_includes/anchor_headings.html +144 -0
- data/docs/_includes/head.html +35 -0
- data/docs/_includes/header.html +58 -0
- data/docs/_layouts/default.html +11 -0
- data/docs/assets/css/rest_framework.css +159 -0
- data/docs/assets/images/favicon.ico +0 -0
- data/docs/assets/js/rest_framework.js +137 -0
- data/docs/index.md +133 -0
- data/lib/rest_framework/serializers.rb +1 -1
- metadata +19 -2
@@ -0,0 +1,35 @@
|
|
1
|
+
<head>
|
2
|
+
<meta charset="utf-8">
|
3
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
4
|
+
<link rel='icon' type='image/x-icon' href='/assets/images/favicon.ico' />
|
5
|
+
|
6
|
+
<title>{% if page.title %}{{ page.title | escape }}{% else %}{{ site.title | escape }}{% endif %}</title>
|
7
|
+
|
8
|
+
<!-- Bootstrap -->
|
9
|
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-aFq/bzH65dt+w6FI2ooMVUpc+21e0SRygnTpmBvdBgSdnuTN7QbdgL+OapgHtvPp" crossorigin="anonymous">
|
10
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha2/dist/js/bootstrap.bundle.min.js" integrity="sha384-qKXV1j0HvMUeCBQ+QVp7JcfGl760yU08IQ+GpUo5hlbpg51QRiuqHAJz8+BrxE/N" crossorigin="anonymous"></script>
|
11
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.4/font/bootstrap-icons.css">
|
12
|
+
|
13
|
+
<!-- Highlight.js -->
|
14
|
+
<link rel="stylesheet" class="rrf-light-mode" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/a11y-light.min.css" integrity="sha512-WDk6RzwygsN9KecRHAfm9HTN87LQjqdygDmkHSJxVkVI7ErCZ8ZWxP6T8RvBujY1n2/E4Ac+bn2ChXnp5rnnHA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
15
|
+
<link rel="stylesheet" class="rrf-dark-mode" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/a11y-dark.min.css" integrity="sha512-Vj6gPCk8EZlqnoveEyuGyYaWZ1+jyjMPg8g4shwyyNlRQl6d3L9At02ZHQr5K6s5duZl/+YKMnM3/8pDhoUphg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
16
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js" integrity="sha512-bgHRAiTjGrzHzLyKOnpFvaEpGzJet3z4tZnXGjpsCcqOnAH6VGUx9frc5bcIhKTVLEiCO6vEhNAgx5jtLUYrfA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
17
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/shell.min.js" integrity="sha512-X2JngetHwVsp0j3n6lo8HGdXQKLpz2hwFfQkG996OfanpFaQJFgjKJlmzsdefWsHTQIwY539tD09JF48kCPMXw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
18
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/erb.min.js" integrity="sha512-flbEiCcectGeyRXyuMZW5jlAGIQ1/qrTZS6DsZDTqObM0JG/isYHvUyehOyt14ssmY85gZRYra+IJR9+azRuqw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
19
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/ruby.min.js" integrity="sha512-xRUQANk9Iw3wtAp0cBOa1Ghr7yIFrMiJiEujrMGf04qOau23exxj4R7DLUeLGfLiDbVSK0FyN8v2ns4m/6iNmQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
20
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/json.min.js" integrity="sha512-0xYvyncS9OLE7GOpNBZFnwyh9+bq4HVgk4yVVYI678xRvE22ASicF1v6fZ1UiST+M6pn17MzFZdvVCI3jTHSyw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
21
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/languages/xml.min.js" integrity="sha512-5zBcw+OKRkaNyvUEPlTSfYylVzgpi7KpncY36b0gRudfxIYIH0q0kl2j26uCUB3YBRM6ytQQEZSgRg+ZlBTmdA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
22
|
+
|
23
|
+
<link rel="stylesheet" href="{{ "/assets/css/rest_framework.css" }}">
|
24
|
+
<script src="{{ "/assets/js/rest_framework.js" }}"></script>
|
25
|
+
|
26
|
+
<!-- Global site tag (gtag.js) - Google Analytics -->
|
27
|
+
<script async src="https://www.googletagmanager.com/gtag/js?id=G-P2KRPNXQMT"></script>
|
28
|
+
<script>
|
29
|
+
window.dataLayer = window.dataLayer || [];
|
30
|
+
function gtag(){dataLayer.push(arguments);}
|
31
|
+
gtag('js', new Date());
|
32
|
+
|
33
|
+
gtag('config', 'G-P2KRPNXQMT');
|
34
|
+
</script>
|
35
|
+
</head>
|
@@ -0,0 +1,58 @@
|
|
1
|
+
<header>
|
2
|
+
<div class="w-100 m-0 p-0" id="rrfAccentBar"></div>
|
3
|
+
<nav class="navbar py-0 navbar-expand-md" data-bs-theme="dark">
|
4
|
+
<div class="container">
|
5
|
+
|
6
|
+
<span class="navbar-brand p-0">
|
7
|
+
<a href="/">
|
8
|
+
<h1 class="text-light font-weight-light m-0 p-0" style="font-size: 1em; ">{{ site.title }}</h1>
|
9
|
+
</a>
|
10
|
+
</span>
|
11
|
+
|
12
|
+
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent">
|
13
|
+
<span class="navbar-toggler-icon"></span>
|
14
|
+
</button>
|
15
|
+
|
16
|
+
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
17
|
+
<ul class="navbar-nav ms-auto">
|
18
|
+
<li class="nav-item">
|
19
|
+
<a class="nav-link{% if page.url == '/' %} active{% endif %}" href="/">Home</a>
|
20
|
+
</li>
|
21
|
+
|
22
|
+
<li class="nav-item dropdown">
|
23
|
+
<a class="nav-link dropdown-toggle {% if page.url contains 'guide' %} active{% endif %}" href="#" role="button" data-bs-toggle="dropdown">
|
24
|
+
Guide
|
25
|
+
</a>
|
26
|
+
<div class="rrf-mode dropdown-menu">
|
27
|
+
{% for section in site.guide %}
|
28
|
+
<a class="dropdown-item" href="{{ section.url }}">{{ section.title }}</a>
|
29
|
+
{% endfor %}
|
30
|
+
</div>
|
31
|
+
</li>
|
32
|
+
|
33
|
+
<li class="nav-item ps-2" id="rrfGithubAndModeWrapper">
|
34
|
+
<span id="rrfGithubComponent">
|
35
|
+
<script async defer src="https://buttons.github.io/buttons.js"></script>
|
36
|
+
<a class="github-button" href="https://github.com/gregschmit/rails-rest-framework" data-show-count="true" aria-label="Star gregschmit/rails-rest-framework on GitHub">Star</a>
|
37
|
+
</span>
|
38
|
+
<div class="dropdown ms-auto float-end" id="rrfModeComponent">
|
39
|
+
<button class="btn btn-dark dropdown-toggle rounded-0 bg-black" style="border-color: black" data-bs-toggle="dropdown"></button>
|
40
|
+
<div class="rrf-mode dropdown-menu dropdown-menu-end py-0 rounded-0" style="font-size: .8em; min-width: 0">
|
41
|
+
<button class="dropdown-item text-end" data-rrf-mode-value="system">
|
42
|
+
System<i class="bi bi-circle-half ms-2"></i>
|
43
|
+
</button>
|
44
|
+
<button class="dropdown-item text-end" data-rrf-mode-value="light">
|
45
|
+
Light<i class="bi bi-sun-fill ms-2"></i>
|
46
|
+
</button>
|
47
|
+
<button class="dropdown-item text-end" data-rrf-mode-value="dark">
|
48
|
+
Dark<i class="bi bi-moon-stars-fill ms-2"></i>
|
49
|
+
</button>
|
50
|
+
</div>
|
51
|
+
</div>
|
52
|
+
</li>
|
53
|
+
</ul>
|
54
|
+
</div>
|
55
|
+
|
56
|
+
</div>
|
57
|
+
</nav>
|
58
|
+
</header>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html class="rrf-mode">
|
3
|
+
{% include head.html %}
|
4
|
+
<body>
|
5
|
+
{% include header.html %}
|
6
|
+
<div class="container pb-3">
|
7
|
+
<div id="headersTable" class="headers-table float-md-end m-2"></div>
|
8
|
+
{% include anchor_headings.html html=content anchorBody="#" %}
|
9
|
+
</div>
|
10
|
+
</body>
|
11
|
+
</html>
|
@@ -0,0 +1,159 @@
|
|
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
|
+
}
|
Binary file
|
@@ -0,0 +1,137 @@
|
|
1
|
+
/*******************************
|
2
|
+
* START OF LIB/DOCS COMMON JS *
|
3
|
+
*******************************/
|
4
|
+
|
5
|
+
;(() => {
|
6
|
+
// Get the real mode from a selected mode. Anything other than "light" or "dark" is treated as
|
7
|
+
// "system" mode.
|
8
|
+
const rrfGetRealMode = (selectedMode) => {
|
9
|
+
if (selectedMode === "light" || selectedMode === "dark") {
|
10
|
+
return selectedMode
|
11
|
+
}
|
12
|
+
|
13
|
+
if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
14
|
+
return "dark"
|
15
|
+
}
|
16
|
+
|
17
|
+
return "light"
|
18
|
+
}
|
19
|
+
|
20
|
+
// Set the mode, given a "selected" mode.
|
21
|
+
const rrfSetSelectedMode = (selectedMode) => {
|
22
|
+
// Anything except "light" or "dark" is casted to "system".
|
23
|
+
if (selectedMode !== "light" && selectedMode !== "dark") {
|
24
|
+
selectedMode = "system"
|
25
|
+
}
|
26
|
+
|
27
|
+
// Store selected mode in `localStorage`.
|
28
|
+
localStorage.setItem("rrfMode", selectedMode)
|
29
|
+
|
30
|
+
// Set the mode selector to the selected mode.
|
31
|
+
const modeComponent = document.getElementById("rrfModeComponent")
|
32
|
+
if (modeComponent) {
|
33
|
+
let labelHTML
|
34
|
+
modeComponent.querySelectorAll("button[data-rrf-mode-value]").forEach((el) => {
|
35
|
+
if (el.getAttribute("data-rrf-mode-value") === selectedMode) {
|
36
|
+
el.classList.add("active")
|
37
|
+
labelHTML = el.querySelector("i").outerHTML.replace("ms-2", "me-1")
|
38
|
+
} else {
|
39
|
+
el.classList.remove("active")
|
40
|
+
}
|
41
|
+
})
|
42
|
+
modeComponent.querySelector("button[data-bs-toggle]").innerHTML = labelHTML
|
43
|
+
}
|
44
|
+
|
45
|
+
// Get the real mode to use.
|
46
|
+
realMode = rrfGetRealMode(selectedMode)
|
47
|
+
|
48
|
+
// Set the `realMode` effects.
|
49
|
+
if (realMode === "light") {
|
50
|
+
document.querySelectorAll(".rrf-light-mode").forEach((el) => {
|
51
|
+
el.disabled = false
|
52
|
+
})
|
53
|
+
document.querySelectorAll(".rrf-dark-mode").forEach((el) => {
|
54
|
+
el.disabled = true
|
55
|
+
})
|
56
|
+
document.querySelectorAll(".rrf-mode").forEach((el) => {
|
57
|
+
el.setAttribute("data-bs-theme", "light")
|
58
|
+
})
|
59
|
+
} else if (realMode === "dark") {
|
60
|
+
document.querySelectorAll(".rrf-light-mode").forEach((el) => {
|
61
|
+
el.disabled = true
|
62
|
+
})
|
63
|
+
document.querySelectorAll(".rrf-dark-mode").forEach((el) => {
|
64
|
+
el.disabled = false
|
65
|
+
})
|
66
|
+
document.querySelectorAll(".rrf-mode").forEach((el) => {
|
67
|
+
el.setAttribute("data-bs-theme", "dark")
|
68
|
+
})
|
69
|
+
} else {
|
70
|
+
console.log(`RRF: Unknown mode: ${mode}`)
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
// Initialize dark/light mode before page fully loads to prevent flash.
|
75
|
+
rrfSetSelectedMode(localStorage.getItem("rrfMode"))
|
76
|
+
|
77
|
+
// Initialize dark/light mode after page load (mostly so mode component is updated).
|
78
|
+
document.addEventListener("DOMContentLoaded", (event) => {
|
79
|
+
rrfSetSelectedMode(localStorage.getItem("rrfMode"))
|
80
|
+
|
81
|
+
// Also set up mode selector.
|
82
|
+
document.querySelectorAll("#rrfModeComponent button[data-rrf-mode-value]").forEach((el) => {
|
83
|
+
el.addEventListener("click", (event) => {
|
84
|
+
rrfSetSelectedMode(event.target.getAttribute("data-rrf-mode-value"))
|
85
|
+
})
|
86
|
+
})
|
87
|
+
})
|
88
|
+
|
89
|
+
// Handle case where user changes system theme.
|
90
|
+
if (window.matchMedia) {
|
91
|
+
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => {
|
92
|
+
const selectedMode = localStorage.getItem("rrfMode")
|
93
|
+
if (selectedMode !== "light" && selectedMode !== "dark") {
|
94
|
+
rrfSetSelectedMode("system")
|
95
|
+
}
|
96
|
+
})
|
97
|
+
}
|
98
|
+
})()
|
99
|
+
|
100
|
+
/*****************************
|
101
|
+
* END OF LIB/DOCS COMMON JS *
|
102
|
+
*****************************/
|
103
|
+
|
104
|
+
document.addEventListener("DOMContentLoaded", () => {
|
105
|
+
// Initialize `Highlight.js`.
|
106
|
+
hljs.configure({ ignoreUnescapedHTML: true })
|
107
|
+
hljs.highlightAll()
|
108
|
+
|
109
|
+
// Setup the floating table of contents.
|
110
|
+
let table = "<ul>"
|
111
|
+
let hlevel = 2
|
112
|
+
let hprevlevel = 2
|
113
|
+
document.querySelectorAll("h2, h3, h4").forEach((header) => {
|
114
|
+
hlevel = parseInt(header.tagName[1])
|
115
|
+
|
116
|
+
if (hlevel > hprevlevel) {
|
117
|
+
table += "<ul>"
|
118
|
+
} else if (hlevel < hprevlevel) {
|
119
|
+
Array(hprevlevel - hlevel)
|
120
|
+
.fill(0)
|
121
|
+
.forEach(function () {
|
122
|
+
table += "</ul>"
|
123
|
+
})
|
124
|
+
}
|
125
|
+
table += `<li><a href="${
|
126
|
+
header.querySelectorAll("a")[0].href
|
127
|
+
}">${header.childNodes[0].nodeValue.trim()}</a></li>`
|
128
|
+
hprevlevel = hlevel
|
129
|
+
})
|
130
|
+
if (hlevel > hprevlevel) {
|
131
|
+
table += "</ul>"
|
132
|
+
}
|
133
|
+
table += "</ul>"
|
134
|
+
if (table != "<ul></ul>") {
|
135
|
+
document.getElementById("headersTable").innerHTML = table
|
136
|
+
}
|
137
|
+
})
|
data/docs/index.md
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
---
|
2
|
+
---
|
3
|
+
|
4
|
+
# Rails REST Framework
|
5
|
+
|
6
|
+
[](https://badge.fury.io/rb/rest_framework)
|
7
|
+
[](https://github.com/gregschmit/rails-rest-framework/actions/workflows/pipeline.yml)
|
8
|
+
[](https://coveralls.io/github/gregschmit/rails-rest-framework?branch=master)
|
9
|
+
[](https://codeclimate.com/github/gregschmit/rails-rest-framework/maintainability)
|
10
|
+
|
11
|
+
A framework for DRY RESTful APIs in Ruby on Rails.
|
12
|
+
|
13
|
+
**The Problem**: Building controllers for APIs usually involves writing a lot of redundant CRUD
|
14
|
+
logic, and routing them can be obnoxious. Building and maintaining features like ordering,
|
15
|
+
filtering, and pagination can be tedious.
|
16
|
+
|
17
|
+
**The Solution**: This framework implements browsable API responses, CRUD actions for your models,
|
18
|
+
and features like ordering/filtering/pagination, so you can focus on building awesome APIs.
|
19
|
+
|
20
|
+
Website/Guide: [rails-rest-framework.com](https://rails-rest-framework.com)
|
21
|
+
|
22
|
+
Demo: [demo.rails-rest-framework.com](https://demo.rails-rest-framework.com)
|
23
|
+
|
24
|
+
Source: [github.com/gregschmit/rails-rest-framework](https://github.com/gregschmit/rails-rest-framework)
|
25
|
+
|
26
|
+
YARD Docs: [rubydoc.info/gems/rest_framework](https://rubydoc.info/gems/rest_framework)
|
27
|
+
|
28
|
+
## Installation
|
29
|
+
|
30
|
+
Add this line to your application's Gemfile:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
gem 'rest_framework'
|
34
|
+
```
|
35
|
+
|
36
|
+
And then execute:
|
37
|
+
|
38
|
+
```shell
|
39
|
+
$ bundle install
|
40
|
+
```
|
41
|
+
|
42
|
+
Or install it yourself with:
|
43
|
+
|
44
|
+
```shell
|
45
|
+
$ gem install rest_framework
|
46
|
+
```
|
47
|
+
|
48
|
+
## Quick Usage Tutorial
|
49
|
+
|
50
|
+
### Controller Mixins
|
51
|
+
|
52
|
+
To transform a controller into a RESTful controller, you can either include `BaseControllerMixin`,
|
53
|
+
`ReadOnlyModelControllerMixin`, or `ModelControllerMixin`. `BaseControllerMixin` provides a `root`
|
54
|
+
action and a simple interface for routing arbitrary additional actions:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
class ApiController < ApplicationController
|
58
|
+
include RESTFramework::BaseControllerMixin
|
59
|
+
self.extra_actions = {test: [:get]}
|
60
|
+
|
61
|
+
def test
|
62
|
+
render api_response({message: "Test successful!"})
|
63
|
+
end
|
64
|
+
end
|
65
|
+
```
|
66
|
+
|
67
|
+
`ModelControllerMixin` assists with providing the standard model CRUD for your controller.
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
class Api::MoviesController < ApiController
|
71
|
+
include RESTFramework::ModelControllerMixin
|
72
|
+
|
73
|
+
self.recordset = Movie.where(enabled: true)
|
74
|
+
end
|
75
|
+
```
|
76
|
+
|
77
|
+
`ReadOnlyModelControllerMixin` only enables list/show actions, but since we're naming this
|
78
|
+
controller in a way that doesn't make the model obvious, we can set that explicitly:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
class Api::ReadOnlyMoviesController < ApiController
|
82
|
+
include RESTFramework::ReadOnlyModelControllerMixin
|
83
|
+
|
84
|
+
self.model = Movie
|
85
|
+
end
|
86
|
+
```
|
87
|
+
|
88
|
+
Note that you can also override the `get_recordset` instance method to override the API behavior
|
89
|
+
dynamically per-request.
|
90
|
+
|
91
|
+
### Routing
|
92
|
+
|
93
|
+
You can use Rails' `resource`/`resources` routers to route your API, however if you want
|
94
|
+
`extra_actions` / `extra_member_actions` to be routed automatically, then you can use `rest_route`
|
95
|
+
for non-resourceful controllers, or `rest_resource` / `rest_resources` resourceful routers. You can
|
96
|
+
also use `rest_root` to route the root of your API:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
Rails.application.routes.draw do
|
100
|
+
rest_root :api # will find `api_controller` and route the `root` action to '/api'
|
101
|
+
namespace :api do
|
102
|
+
rest_resources :movies
|
103
|
+
rest_resources :users
|
104
|
+
end
|
105
|
+
end
|
106
|
+
```
|
107
|
+
|
108
|
+
Or if you want the API root to be routed to `Api::RootController#root`:
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
Rails.application.routes.draw do
|
112
|
+
namespace :api do
|
113
|
+
rest_root # will route `Api::RootController#root` to '/' in this namespace ('/api')
|
114
|
+
rest_resources :movies
|
115
|
+
rest_resources :users
|
116
|
+
end
|
117
|
+
end
|
118
|
+
```
|
119
|
+
|
120
|
+
## Development/Testing
|
121
|
+
|
122
|
+
After you clone the repository, cd'ing into the directory should create a new gemset if you are
|
123
|
+
using RVM. Then run `bundle install` to install the appropriate gems.
|
124
|
+
|
125
|
+
To run the test suite:
|
126
|
+
|
127
|
+
```shell
|
128
|
+
$ rails test
|
129
|
+
```
|
130
|
+
|
131
|
+
The top-level `bin/rails` proxies all Rails commands to the test project, so you can operate it via
|
132
|
+
the usual commands. Ensure you run `rails db:setup` before running `rails server` or
|
133
|
+
`rails console`.
|
@@ -281,7 +281,7 @@ class RESTFramework::NativeSerializer < RESTFramework::BaseSerializer
|
|
281
281
|
end
|
282
282
|
else
|
283
283
|
self.define_singleton_method(f) do |record|
|
284
|
-
next record.send(f).map
|
284
|
+
next record.send(f).map(&:url)
|
285
285
|
end
|
286
286
|
end
|
287
287
|
elsif @model.method_defined?(f)
|
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.
|
4
|
+
version: 0.9.0
|
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-04-
|
11
|
+
date: 2023-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -40,6 +40,23 @@ files:
|
|
40
40
|
- app/views/rest_framework/_raw_form.html.erb
|
41
41
|
- app/views/rest_framework/_route.html.erb
|
42
42
|
- app/views/rest_framework/_routes.html.erb
|
43
|
+
- docs/CNAME
|
44
|
+
- docs/Gemfile
|
45
|
+
- docs/Gemfile.lock
|
46
|
+
- docs/_config.yml
|
47
|
+
- docs/_guide/1_routers.md
|
48
|
+
- docs/_guide/2_controller_mixins.md
|
49
|
+
- docs/_guide/3_serializers.md
|
50
|
+
- docs/_guide/4_filtering_and_ordering.md
|
51
|
+
- docs/_guide/5_pagination.md
|
52
|
+
- docs/_includes/anchor_headings.html
|
53
|
+
- docs/_includes/head.html
|
54
|
+
- docs/_includes/header.html
|
55
|
+
- docs/_layouts/default.html
|
56
|
+
- docs/assets/css/rest_framework.css
|
57
|
+
- docs/assets/images/favicon.ico
|
58
|
+
- docs/assets/js/rest_framework.js
|
59
|
+
- docs/index.md
|
43
60
|
- lib/rest_framework.rb
|
44
61
|
- lib/rest_framework/controller_mixins.rb
|
45
62
|
- lib/rest_framework/controller_mixins/base.rb
|