rest_framework 0.9.5 → 0.9.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +130 -0
  4. data/VERSION +1 -1
  5. data/app/views/layouts/rest_framework.html.erb +9 -183
  6. data/app/views/rest_framework/_breadcrumbs.html.erb +27 -0
  7. data/app/views/rest_framework/_head.html.erb +347 -190
  8. data/app/views/rest_framework/_header.html.erb +15 -0
  9. data/app/views/rest_framework/_heading.html.erb +10 -0
  10. data/app/views/rest_framework/_payloads.html.erb +36 -0
  11. data/app/views/rest_framework/_request_metadata.html.erb +16 -0
  12. data/app/views/rest_framework/_routes_and_forms.html.erb +52 -0
  13. data/app/views/rest_framework/head/_external.html.erb +7 -2
  14. data/app/views/rest_framework/header/_mode.html.erb +14 -0
  15. data/app/views/rest_framework/heading/_actions.html.erb +9 -0
  16. data/app/views/rest_framework/{_routes.html.erb → routes_and_forms/_routes.html.erb} +2 -2
  17. data/lib/rest_framework/controller_mixins/base.rb +11 -12
  18. data/lib/rest_framework/engine.rb +5 -3
  19. data/lib/rest_framework/filters/ransack.rb +6 -6
  20. data/lib/rest_framework/version.rb +3 -8
  21. data/lib/rest_framework.rb +11 -2
  22. data/vendor/assets/javascripts/rest_framework/external.min.js +1256 -0
  23. data/vendor/assets/stylesheets/rest_framework/{bootstrap-icons.min.css → external.min.css} +415 -0
  24. data/vendor/assets/stylesheets/rest_framework/highlight-a11y-dark.min.css +1 -1
  25. data/vendor/assets/stylesheets/rest_framework/highlight-a11y-light.min.css +1 -1
  26. metadata +16 -33
  27. data/README.md +0 -1
  28. data/app/views/rest_framework/head/_shared.html +0 -164
  29. data/docs/CNAME +0 -1
  30. data/docs/Gemfile +0 -5
  31. data/docs/Gemfile.lock +0 -264
  32. data/docs/_config.yml +0 -19
  33. data/docs/_guide/1_routers.md +0 -110
  34. data/docs/_guide/2_controllers.md +0 -342
  35. data/docs/_guide/3_serializers.md +0 -60
  36. data/docs/_guide/4_filtering_and_ordering.md +0 -41
  37. data/docs/_guide/5_pagination.md +0 -21
  38. data/docs/_includes/anchor_headings.html +0 -144
  39. data/docs/_includes/external.html +0 -9
  40. data/docs/_includes/head.html +0 -155
  41. data/docs/_includes/header.html +0 -58
  42. data/docs/_includes/shared.html +0 -164
  43. data/docs/_layouts/default.html +0 -11
  44. data/docs/assets/images/favicon.ico +0 -0
  45. data/docs/index.md +0 -133
  46. data/vendor/assets/javascripts/rest_framework/bootstrap.min.js +0 -6
  47. data/vendor/assets/javascripts/rest_framework/highlight-json.min.js +0 -7
  48. data/vendor/assets/javascripts/rest_framework/highlight-xml.min.js +0 -29
  49. data/vendor/assets/javascripts/rest_framework/highlight.min.js +0 -1202
  50. data/vendor/assets/javascripts/rest_framework/neatjson.min.js +0 -7
  51. data/vendor/assets/javascripts/rest_framework/trix.min.js +0 -6
  52. data/vendor/assets/stylesheets/rest_framework/bootstrap.min.css +0 -5
  53. data/vendor/assets/stylesheets/rest_framework/trix.min.css +0 -410
  54. /data/app/views/rest_framework/{_html_form.html.erb → routes_and_forms/_html_form.html.erb} +0 -0
  55. /data/app/views/rest_framework/{_raw_form.html.erb → routes_and_forms/_raw_form.html.erb} +0 -0
  56. /data/app/views/rest_framework/{_route.html.erb → routes_and_forms/routes/_route.html.erb} +0 -0
@@ -1,155 +0,0 @@
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
- {% include external.html %}
9
- {% include shared.html %}
10
-
11
- <style>
12
- /* Header adjustments. */
13
- h1, h2, h3, h4, h5, h6 {
14
- width: 100%;
15
- font-weight: normal;
16
- margin-top: 1.8rem;
17
- margin-bottom: 1.2rem;
18
- }
19
- h1 a:not(:hover),
20
- h2 a:not(:hover),
21
- h3 a:not(:hover),
22
- h4 a:not(:hover),
23
- h5 a:not(:hover),
24
- h6 a:not(:hover) {
25
- color: #ddd;
26
- }
27
- html[data-bs-theme="dark"] h1 a:not(:hover),
28
- html[data-bs-theme="dark"] h2 a:not(:hover),
29
- html[data-bs-theme="dark"] h3 a:not(:hover),
30
- html[data-bs-theme="dark"] h4 a:not(:hover),
31
- html[data-bs-theme="dark"] h5 a:not(:hover),
32
- html[data-bs-theme="dark"] h6 a:not(:hover) {
33
- color: #444;
34
- }
35
- h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover {
36
- text-decoration: none !important;
37
- }
38
-
39
- /* Navbar */
40
- .navbar .navbar-toggler {
41
- margin: .2em 0;
42
- padding: .2em .3em;
43
- border: none;
44
- }
45
- .navbar .navbar-toggler .navbar-toggler-icon {
46
- height: 1.1em;
47
- width: 1.1em;
48
- }
49
- .navbar .navbar-nav .nav-item .nav-link {
50
- padding: .45em .6em;
51
- }
52
- .navbar .navbar-nav .nav-item .nav-link:hover {
53
- background-color: #262a2f;
54
- }
55
- .navbar .dropdown-menu a.dropdown-item {
56
- font-size: .9em;
57
- padding: .2em .8em;
58
- }
59
-
60
- /* Headers table. */
61
- .headers-table {
62
- padding: .5em 1em;
63
- background-color: #eee;
64
- border: 1px solid #aaa;
65
- border-radius: .3em;
66
- font-size: .9em;
67
- }
68
- html[data-bs-theme="dark"] .headers-table {
69
- background-color: #2b2b2b;
70
- }
71
- .headers-table:empty { display: none; }
72
- .headers-table ul {
73
- list-style-type: none;
74
- margin: 0;
75
- padding-left: 0;
76
- padding-right: .6em;
77
- }
78
- .headers-table ul li { margin: .3em 0; }
79
- .headers-table ul ul { padding-left: .8em; padding-right: 0; }
80
- .headers-table > ul > li {
81
- font-weight: bold;
82
- }
83
-
84
- /* Style the github and mode component. */
85
- #rrfGithubAndModeWrapper {
86
- height: 2.4em;
87
- }
88
- #rrfGithubComponent {
89
- display: inline-block;
90
- position: relative;
91
- top: .6em;
92
- }
93
- #rrfModeComponent .dropdown-toggle {
94
- float: right;
95
- }
96
- #rrfModeComponent .dropdown-menu {
97
- position: absolute;
98
- right: 0;
99
- left: auto;
100
- top: 100%;
101
- }
102
- </style>
103
-
104
- <script>
105
- document.addEventListener("DOMContentLoaded", () => {
106
- // Initialize `Highlight.js`.
107
- hljs.configure({ ignoreUnescapedHTML: true })
108
- hljs.highlightAll()
109
-
110
- // Setup the floating table of contents.
111
- let table = "<ul>"
112
- let hlevel = 2
113
- let hprevlevel = 2
114
- document.querySelectorAll("h2, h3, h4").forEach((header) => {
115
- hlevel = parseInt(header.tagName[1])
116
-
117
- if (hlevel > hprevlevel) {
118
- table += "<ul>"
119
- } else if (hlevel < hprevlevel) {
120
- Array(hprevlevel - hlevel)
121
- .fill(0)
122
- .forEach(function () {
123
- table += "</ul>"
124
- })
125
- }
126
- table += `<li><a href="${
127
- header.querySelectorAll("a")[0].href
128
- }">${header.childNodes[0].nodeValue.trim()}</a></li>`
129
- hprevlevel = hlevel
130
- })
131
- if (hlevel > hprevlevel) {
132
- table += "</ul>"
133
- }
134
- table += "</ul>"
135
- if (table != "<ul></ul>") {
136
- document.getElementById("headersTable").innerHTML = table
137
- }
138
- })
139
- </script>
140
-
141
- <!-- Extra Highlight.js languages not shared with the library. -->
142
- <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>
143
- <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>
144
- <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>
145
-
146
- <!-- Google Analytics: Global Site Tag -->
147
- <script async src="https://www.googletagmanager.com/gtag/js?id=G-P2KRPNXQMT"></script>
148
- <script>
149
- window.dataLayer = window.dataLayer || [];
150
- function gtag(){dataLayer.push(arguments);}
151
- gtag('js', new Date());
152
-
153
- gtag('config', 'G-P2KRPNXQMT');
154
- </script>
155
- </head>
@@ -1,58 +0,0 @@
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>
@@ -1,164 +0,0 @@
1
- <!--
2
- AUTOGENERATED
3
- Updates must be written to `shared.{css,js}` and synced with `rake maintain_assets`.
4
- -->
5
- <style>
6
- :root {
7
- --rrf-red: #900;
8
- --rrf-red-hover: #5f0c0c;
9
- --rrf-light-red: #db2525;
10
- --rrf-light-red-hover: #b80404;
11
- }
12
- #rrfAccentBar {
13
- background-color: var(--rrf-red);
14
- height: .3em;
15
- }
16
- header nav { background-color: black; }
17
-
18
- /* Header adjustments. */
19
- h1 { font-size: 2rem; }
20
- h2 { font-size: 1.7rem; }
21
- h3 { font-size: 1.5rem; }
22
- h4 { font-size: 1.3rem; }
23
- h5 { font-size: 1.1rem; }
24
- h6 { font-size: 1rem; }
25
- h1, h2, h3, h4, h5, h6 {
26
- color: var(--rrf-red);
27
- }
28
- html[data-bs-theme="dark"] h1,
29
- html[data-bs-theme="dark"] h2,
30
- html[data-bs-theme="dark"] h3,
31
- html[data-bs-theme="dark"] h4,
32
- html[data-bs-theme="dark"] h5,
33
- html[data-bs-theme="dark"] h6 {
34
- color: var(--rrf-light-red);
35
- }
36
-
37
- /* Improve code and code blocks. */
38
- pre code, .trix-content pre {
39
- display: block;
40
- overflow-x: auto;
41
- padding: .5em !important;
42
- }
43
- code, .trix-content pre {
44
- --bs-code-color: black;
45
- background-color: #eee !important;
46
- border: 1px solid #aaa;
47
- border-radius: 3px;
48
- padding: .1em .3em;
49
- }
50
- html[data-bs-theme="dark"] code, html[data-bs-theme="dark"] .trix-content pre {
51
- --bs-code-color: white;
52
- background-color: #2b2b2b !important;
53
- }
54
-
55
- /* Anchors */
56
- a:not(.nav-link) {
57
- text-decoration: none;
58
- color: var(--rrf-red);
59
- }
60
- a:hover:not(.nav-link) {
61
- text-decoration: underline;
62
- color: var(--rrf-red-hover);
63
- }
64
- html[data-bs-theme="dark"] a:not(.nav-link) { color: var(--rrf-light-red); }
65
- html[data-bs-theme="dark"] a:hover:not(.nav-link) { color: var(--rrf-light-red-hover); }
66
-
67
- </style>
68
- <script>
69
- ;(() => {
70
- // Get the real mode from a selected mode. Anything other than "light" or "dark" is treated as
71
- // "system" mode.
72
- const rrfGetRealMode = (selectedMode) => {
73
- if (selectedMode === "light" || selectedMode === "dark") {
74
- return selectedMode
75
- }
76
-
77
- if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
78
- return "dark"
79
- }
80
-
81
- return "light"
82
- }
83
-
84
- // Set the mode, given a "selected" mode.
85
- const rrfSetSelectedMode = (selectedMode) => {
86
- // Anything except "light" or "dark" is casted to "system".
87
- if (selectedMode !== "light" && selectedMode !== "dark") {
88
- selectedMode = "system"
89
- }
90
-
91
- // Store selected mode in `localStorage`.
92
- localStorage.setItem("rrfMode", selectedMode)
93
-
94
- // Set the mode selector to the selected mode.
95
- const modeComponent = document.getElementById("rrfModeComponent")
96
- if (modeComponent) {
97
- let labelHTML
98
- modeComponent.querySelectorAll("button[data-rrf-mode-value]").forEach((el) => {
99
- if (el.getAttribute("data-rrf-mode-value") === selectedMode) {
100
- el.classList.add("active")
101
- labelHTML = el.querySelector("i").outerHTML.replace("ms-2", "me-1")
102
- } else {
103
- el.classList.remove("active")
104
- }
105
- })
106
- modeComponent.querySelector("button[data-bs-toggle]").innerHTML = labelHTML
107
- }
108
-
109
- // Get the real mode to use.
110
- realMode = rrfGetRealMode(selectedMode)
111
-
112
- // Set the `realMode` effects.
113
- if (realMode === "light") {
114
- document.querySelectorAll(".rrf-light-mode").forEach((el) => {
115
- el.disabled = false
116
- })
117
- document.querySelectorAll(".rrf-dark-mode").forEach((el) => {
118
- el.disabled = true
119
- })
120
- document.querySelectorAll(".rrf-mode").forEach((el) => {
121
- el.setAttribute("data-bs-theme", "light")
122
- })
123
- } else if (realMode === "dark") {
124
- document.querySelectorAll(".rrf-light-mode").forEach((el) => {
125
- el.disabled = true
126
- })
127
- document.querySelectorAll(".rrf-dark-mode").forEach((el) => {
128
- el.disabled = false
129
- })
130
- document.querySelectorAll(".rrf-mode").forEach((el) => {
131
- el.setAttribute("data-bs-theme", "dark")
132
- })
133
- } else {
134
- console.log(`RRF: Unknown mode: ${mode}`)
135
- }
136
- }
137
-
138
- // Initialize dark/light mode before page fully loads to prevent flash.
139
- rrfSetSelectedMode(localStorage.getItem("rrfMode"))
140
-
141
- // Initialize dark/light mode after page load (mostly so mode component is updated).
142
- document.addEventListener("DOMContentLoaded", (event) => {
143
- rrfSetSelectedMode(localStorage.getItem("rrfMode"))
144
-
145
- // Also set up mode selector.
146
- document.querySelectorAll("#rrfModeComponent button[data-rrf-mode-value]").forEach((el) => {
147
- el.addEventListener("click", (event) => {
148
- rrfSetSelectedMode(event.target.getAttribute("data-rrf-mode-value"))
149
- })
150
- })
151
- })
152
-
153
- // Handle case where user changes system theme.
154
- if (window.matchMedia) {
155
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => {
156
- const selectedMode = localStorage.getItem("rrfMode")
157
- if (selectedMode !== "light" && selectedMode !== "dark") {
158
- rrfSetSelectedMode("system")
159
- }
160
- })
161
- }
162
- })()
163
-
164
- </script>
@@ -1,11 +0,0 @@
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>
Binary file
data/docs/index.md DELETED
@@ -1,133 +0,0 @@
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`.