rest_framework 0.8.16 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ [![Gem Version](https://badge.fury.io/rb/rest_framework.svg)](https://badge.fury.io/rb/rest_framework)
7
+ [![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)
8
+ [![Coverage](https://coveralls.io/repos/github/gregschmit/rails-rest-framework/badge.svg?branch=master)](https://coveralls.io/github/gregschmit/rails-rest-framework?branch=master)
9
+ [![Maintainability](https://api.codeclimate.com/v1/badges/ba5df7706cb544d78555/maintainability)](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 { |x| x.attachment&.url }
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.8.16
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-03 00:00:00.000000000 Z
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