resting_pug 0.1.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +54 -0
- data/Rakefile +23 -0
- data/lib/resting_pug.rb +4 -0
- data/lib/resting_pug/actions.rb +168 -0
- data/lib/resting_pug/base.rb +28 -0
- data/lib/resting_pug/chains.rb +56 -0
- data/lib/resting_pug/modificators.rb +31 -0
- data/lib/resting_pug/params.rb +189 -0
- data/lib/resting_pug/render.rb +72 -0
- data/lib/resting_pug/subject.rb +87 -0
- data/lib/resting_pug/version.rb +3 -0
- data/lib/tasks/resting_pug_tasks.rake +4 -0
- metadata +157 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f7d99d102f6977a7fce1ac74ae7b1489d95273d7
|
4
|
+
data.tar.gz: ba714667deb6cfc2bc48a39085bf1f18a2954845
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 062416d0fe7ee490e6ddd9cfb7b7b3fe8cd94d738a5579e0d8801794dd940012a9c3ccf456b223e42a2d41cc4c5f82d0d61857c7d62663378748fff484e9f487
|
7
|
+
data.tar.gz: ebb18d667055f77993629cb8320920e410fed4b221dde060ab0709a267ceb11d46701ad1e168bf70708ac88e2c478a69e06b127ef6dab818d71520dc9007356b
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2017 Slava Korolev
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
|
2
|
+
<h1 align="center">
|
3
|
+
<br>
|
4
|
+
<a href="https://korolvs.github.com/resting_pug"><img src="https://korolvs.github.com/resting_pug/resting_pug.png" alt="Markdownify" width="80%"></a>
|
5
|
+
<br>
|
6
|
+
</h1>
|
7
|
+
|
8
|
+
# Basic Overview
|
9
|
+
Resting Pug allows you to create a JSON API with just adding one line to your controller and fully customize it with overriding small and simple helper methods.
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
Include ```RestingPug::Base``` into controller to add CRUD actions to it:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
class BooksController < ApplicationController
|
16
|
+
include RestingPug::Base
|
17
|
+
end
|
18
|
+
```
|
19
|
+
|
20
|
+
You can add CRUD actions to all controllers by including this module into ```ApplicationController```:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
class ApplicationController < ActionController::Base
|
24
|
+
include RestingPug::Base
|
25
|
+
end
|
26
|
+
```
|
27
|
+
|
28
|
+
Don't forget to add a route to ```config/routes.rb```
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
Rails.application.routes.draw do
|
32
|
+
resources :books
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
## Installation
|
37
|
+
Add this line to your application's Gemfile:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
gem 'resting_pug'
|
41
|
+
```
|
42
|
+
|
43
|
+
And then execute:
|
44
|
+
```bash
|
45
|
+
$ bundle
|
46
|
+
```
|
47
|
+
|
48
|
+
## Contributing
|
49
|
+
Contribution directions go here.
|
50
|
+
|
51
|
+
## License
|
52
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
53
|
+
|
54
|
+
Logo is [Designed by Freepik](https://www.freepik.com/free-vector/happy-pug-resting-on-the-sofa_1357299.htm)
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'RestingPug'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
require 'bundler/gem_tasks'
|
23
|
+
|
data/lib/resting_pug.rb
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
module RestingPug
|
2
|
+
# Describes basic CRUD actions
|
3
|
+
# @see https://en.wikipedia.org/wiki/Create,_read,_update_and_delete
|
4
|
+
# @used_in {Base.included}
|
5
|
+
module Actions
|
6
|
+
# Creates a subject with attributes from params and returns it.
|
7
|
+
# @example
|
8
|
+
# Request:
|
9
|
+
# POST http://your.awesome/api/books
|
10
|
+
# {
|
11
|
+
# "name": "11/22/63",
|
12
|
+
# "author": "Stephen King"
|
13
|
+
# }
|
14
|
+
#
|
15
|
+
# Response:
|
16
|
+
# 200 OK
|
17
|
+
# {
|
18
|
+
# "book": {
|
19
|
+
# "id": 1,
|
20
|
+
# "name": "11/22/63",
|
21
|
+
# "author": "Stephen King"
|
22
|
+
# }
|
23
|
+
# }
|
24
|
+
# @note You can sustomize creating action:
|
25
|
+
# - override {Subject#subject_model} to set what model will be created
|
26
|
+
# - override {Chains#create_chain} to add or remove methods which will be called while creating a subject
|
27
|
+
# - override {Params#permitted_fields_for_create} to set which params can be set in a new subject
|
28
|
+
# - override {Params#permitted_fields_for_show} to set which params will be shown in response
|
29
|
+
# - override {Render#decide_what_to_render} to set how it will be decided what to render in response
|
30
|
+
# - override {Render#render_subject} to set how subject will be rendered
|
31
|
+
# - override {Render#render_errors} to set how errors will be rendered
|
32
|
+
# @use {#run_chain}
|
33
|
+
# @use {Chains#create_chain}
|
34
|
+
def create
|
35
|
+
run_chain(create_chain)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Updates a subject by id with attributes from params and returns it.
|
39
|
+
# @example
|
40
|
+
# Request:
|
41
|
+
# PATCH http://your.awesome/api/books/1
|
42
|
+
# {
|
43
|
+
# "name": "The Green Mile",
|
44
|
+
# }
|
45
|
+
#
|
46
|
+
# Response:
|
47
|
+
# 200 OK
|
48
|
+
# {
|
49
|
+
# "book": {
|
50
|
+
# "id": 1,
|
51
|
+
# "name": "The Green Mile",
|
52
|
+
# "author": "Stephen King"
|
53
|
+
# }
|
54
|
+
# }
|
55
|
+
# @note You can sustomize creating action:
|
56
|
+
# - override {Subject#subject_model} to set what model will be updated
|
57
|
+
# - override {Chains#update_chain} to add or remove methods which will be called while updating a subject
|
58
|
+
# - override {Params#permitted_fields_for_update} to set which params can be updated
|
59
|
+
# - override {Params#permitted_fields_for_show} to set which params will be shown in response
|
60
|
+
# - override {Render#decide_what_to_render} to set how it will be decided what to render in response
|
61
|
+
# - override {Render#render_subject} to set how subject will be rendered
|
62
|
+
# - override {Render#render_errors} to set how errors will be rendered
|
63
|
+
# - override {Render#render_not_found} to set what to render when subject with ID from params is not found
|
64
|
+
# @use {#run_chain}
|
65
|
+
# @use {Chains#update_chain}
|
66
|
+
def update
|
67
|
+
run_chain(update_chain)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Destroys a subject by id
|
71
|
+
# @example
|
72
|
+
# Request:
|
73
|
+
# DELETE http://your.awesome/api/books/1
|
74
|
+
#
|
75
|
+
# Response:
|
76
|
+
# 204 No Content
|
77
|
+
# @note You can sustomize creating action:
|
78
|
+
# - override {Subject#subject_model} to set what model will be deleted
|
79
|
+
# - override {Chains#destroy_chain} to add or remove methods which will be called while deleting a subject
|
80
|
+
# - override {Subject#destroy_subject} to set how it will be destroyed
|
81
|
+
# - override {Render#render_nothing} to set what to render when subject is destroyed
|
82
|
+
# - override {Render#render_errors} to set how errors will be rendered
|
83
|
+
# - override {Render#render_not_found} to set what to render when subject with ID from params is not found
|
84
|
+
# @use {#run_chain}
|
85
|
+
# @use {Chains#destroy_chain}
|
86
|
+
def destroy
|
87
|
+
run_chain(destroy_chain)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Shows a subject by id
|
91
|
+
# @example
|
92
|
+
# Request:
|
93
|
+
# GET http://your.awesome/api/books/1
|
94
|
+
#
|
95
|
+
# Response:
|
96
|
+
# 200 OK
|
97
|
+
# {
|
98
|
+
# "book": {
|
99
|
+
# "id": 1,
|
100
|
+
# "name": "The Green Mile",
|
101
|
+
# "author": "Stephen King"
|
102
|
+
# }
|
103
|
+
# }
|
104
|
+
# @note You can sustomize creating action:
|
105
|
+
# - override {Subject#subject_model} to set what model will be shown
|
106
|
+
# - override {Chains#show_chain} to add or remove methods which will be called while updating a subject
|
107
|
+
# - override {Params#permitted_fields_for_show} to set which params will be shown in response
|
108
|
+
# - override {Render#render_subject} to set how subject will be rendered
|
109
|
+
# - override {Render#render_not_found} to set what to render when subject with ID from params is not found
|
110
|
+
# @use {#run_chain}
|
111
|
+
# @use {Chains#show_chain}
|
112
|
+
def show
|
113
|
+
run_chain(show_chain)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Shows a list of subjects.
|
117
|
+
# You can filter subjects by attributes using *filter* param.
|
118
|
+
# You can sort subjects using *sort* param. It is a string of comma-separated attributes with minus before attributes you wants to sort descending.
|
119
|
+
# You can paginate subjcts with *page* and *per_page* params.
|
120
|
+
# @example
|
121
|
+
# Request:
|
122
|
+
# GET http://your.awesome/api/books
|
123
|
+
# GET http://your.awesome/api/books?filter[author]="King"
|
124
|
+
# GET http://your.awesome/api/books?filter[author][]="King"&filter[author][]="Kesey"
|
125
|
+
# GET http://your.awesome/api/books?sort=-id,name,-author
|
126
|
+
# GET http://your.awesome/api/books?page=3&per_page=10
|
127
|
+
# GET http://your.awesome/api/books?filter[author]="King"&sort=-id?page=3&per_page=10
|
128
|
+
#
|
129
|
+
# Response:
|
130
|
+
# 200 OK
|
131
|
+
# {
|
132
|
+
# "books": [{
|
133
|
+
# "id": 2,
|
134
|
+
# "name": "The Green Mile",
|
135
|
+
# "author": "Stephen King"
|
136
|
+
# }, {
|
137
|
+
# "id": 1,
|
138
|
+
# "name": "11/22/63",
|
139
|
+
# "author": "Stephen King"
|
140
|
+
# }]
|
141
|
+
# }
|
142
|
+
# @note You can sustomize creating action:
|
143
|
+
# - override {Subject#subject_model} to set what model will be shown
|
144
|
+
# - override {Chains#index_chain} to add or remove methods which will be called while updating a subject
|
145
|
+
# - override {Params#permitted_fields_for_show} to set which params will be shown in response
|
146
|
+
# - override {Params#permitted_fields_for_filter} to set which params can be used for filtering
|
147
|
+
# - override {Params#permitted_fields_for_sort} to set which params can be used for sorting
|
148
|
+
# - override {Params#default_sort_params} to set default sort params
|
149
|
+
# - override {Params#per_page_default} to set default per_page param
|
150
|
+
# - override {Params#per_page_range} to set minimum and maximum possible per_page value
|
151
|
+
# - override {Render#render_subjects} to set how subjects will be rendered
|
152
|
+
# @use {#run_chain}
|
153
|
+
# @use {Chains#index_chain}
|
154
|
+
def index
|
155
|
+
run_chain(index_chain)
|
156
|
+
end
|
157
|
+
|
158
|
+
protected
|
159
|
+
|
160
|
+
# Executes each method in a chain one by one
|
161
|
+
# @param chain [Array] array of methods to execute
|
162
|
+
def run_chain(chain)
|
163
|
+
chain.each do |action|
|
164
|
+
self.send(action)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative './actions'
|
2
|
+
require_relative './chains'
|
3
|
+
require_relative './render'
|
4
|
+
require_relative './subject'
|
5
|
+
require_relative './params'
|
6
|
+
require_relative './modificators'
|
7
|
+
require 'will_paginate/active_record'
|
8
|
+
|
9
|
+
module RestingPug
|
10
|
+
# Main module
|
11
|
+
module Base
|
12
|
+
# Includes all methods in controller
|
13
|
+
# @param base [ActionController::Base]
|
14
|
+
def self.included(base)
|
15
|
+
base.class_eval do
|
16
|
+
include RestingPug::Actions
|
17
|
+
include RestingPug::Chains
|
18
|
+
include RestingPug::Render
|
19
|
+
include RestingPug::Subject
|
20
|
+
include RestingPug::Params
|
21
|
+
include RestingPug::Modificators
|
22
|
+
|
23
|
+
rescue_from ActionController::ParameterMissing, with: :render_param_missing
|
24
|
+
rescue_from ActiveRecord::RecordNotFound, with: :render_not_found
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module RestingPug
|
2
|
+
# Describes chains of methods for actions. Each chain is an array of methods running one by one.
|
3
|
+
# @used_in {Base.included}
|
4
|
+
module Chains
|
5
|
+
protected
|
6
|
+
|
7
|
+
# Creates a chain of methods for creating a subject
|
8
|
+
# @note Override this method to add or remove methods executed while creating a subject
|
9
|
+
# @used_in {Actions#create}
|
10
|
+
# @use {Subject#create_subject}
|
11
|
+
# @use {Render#decide_what_to_render}
|
12
|
+
def create_chain
|
13
|
+
[:create_subject, :decide_what_to_render]
|
14
|
+
end
|
15
|
+
|
16
|
+
# Creates a chain of methods for updating a subject
|
17
|
+
# @note Override this method to add or remove methods executed while updating a subject
|
18
|
+
# @used_in {Actions#update}
|
19
|
+
# @use {Subject#fetch_subject}
|
20
|
+
# @use {Subject#update_subject}
|
21
|
+
# @use {Render#decide_what_to_render}
|
22
|
+
def update_chain
|
23
|
+
[:fetch_subject, :update_subject, :decide_what_to_render]
|
24
|
+
end
|
25
|
+
|
26
|
+
# Creates a chain of methods for deleting a subject
|
27
|
+
# @note Override this method to add or remove methods executed while deleting a subject
|
28
|
+
# @used_in {Actions#destroy}
|
29
|
+
# @use {Subject#fetch_subject}
|
30
|
+
# @use {Subject#destroy_subject}
|
31
|
+
def destroy_chain
|
32
|
+
[:fetch_subject, :destroy_subject]
|
33
|
+
end
|
34
|
+
|
35
|
+
# Creates a chain of methods for showing a subject
|
36
|
+
# @note Override this method to add or remove methods executed while showing a subject
|
37
|
+
# @used_in {Actions#show}
|
38
|
+
# @use {Subject#fetch_subject}
|
39
|
+
# @use {Render#render_subject}
|
40
|
+
def show_chain
|
41
|
+
[:fetch_subject, :render_subject]
|
42
|
+
end
|
43
|
+
|
44
|
+
# Creates a chain of methods for showing a list of subjects
|
45
|
+
# @note Override this method to add or remove methods executed while showing a list of subjects
|
46
|
+
# @used_in {Actions#index}
|
47
|
+
# @use {Subject#fetch_subjects}
|
48
|
+
# @use {Modificators#filter_subjects}
|
49
|
+
# @use {Modificators#sort_subjects}
|
50
|
+
# @use {Modificators#paginate_subjects}
|
51
|
+
# @use {Render#render_subjects}
|
52
|
+
def index_chain
|
53
|
+
[:fetch_subjects, :filter_subjects, :sort_subjects, :paginate_subjects, :render_subjects]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module RestingPug
|
2
|
+
# Describes methods which modificate subject/subjects
|
3
|
+
# @used_in {Base.included}
|
4
|
+
module Modificators
|
5
|
+
protected
|
6
|
+
|
7
|
+
# Selects certain page from all subjects using pagination params
|
8
|
+
# @note Override this method to change pagination of subjects
|
9
|
+
# @used_in {Chains#index_chain}
|
10
|
+
# @use {Params#pagination_params}
|
11
|
+
def paginate_subjects
|
12
|
+
@subjects = @subjects.paginate(page: pagination_params[:page], per_page: pagination_params[:per_page])
|
13
|
+
end
|
14
|
+
|
15
|
+
# Sorts subjects using sorting params
|
16
|
+
# @note Override this method to change sorting of subjects
|
17
|
+
# @used_in {Chains#index_chain}
|
18
|
+
# @use {Params#sort_params}
|
19
|
+
def sort_subjects
|
20
|
+
@subjects = @subjects.order(sort_params)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Filters subjects using filter params
|
24
|
+
# @note Override this method to change how subjects are filtered
|
25
|
+
# @used_in {Chains#index_chain}
|
26
|
+
# @use {Params#pagination_params}
|
27
|
+
def filter_subjects
|
28
|
+
@subjects = @subjects.where(filter_params)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
module RestingPug
|
2
|
+
# Describes transformations with params
|
3
|
+
# @used_in {Base.included}
|
4
|
+
module Params
|
5
|
+
protected
|
6
|
+
|
7
|
+
### PERMITTED FIELDS
|
8
|
+
|
9
|
+
# Returns an array with all fields that API can use
|
10
|
+
# @note Override this method to add or remove fields that you don't want API to use.
|
11
|
+
# @return [Array] of symbols representing attributes
|
12
|
+
# @used_in {#permitted_fields_for_show}
|
13
|
+
# @used_in {#permitted_fields_for_create}
|
14
|
+
# @used_in {#permitted_fields_for_update}
|
15
|
+
# @used_in {#permitted_fields_for_sort}
|
16
|
+
# @used_in {#permitted_fields_for_filter}
|
17
|
+
# @use {Subject#subject_model}
|
18
|
+
def permitted_fields
|
19
|
+
subject_model.column_names.map(&:to_sym)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns an array with all fields that API will show
|
23
|
+
# @note Override this method to add or remove fields that you don't want API to show.
|
24
|
+
# @return [Array] of symbols representing attributes
|
25
|
+
# @used_in {Render#render_subject}
|
26
|
+
# @used_in {Render#render_subjects}
|
27
|
+
# @use {#permitted_fields}
|
28
|
+
def permitted_fields_for_show
|
29
|
+
permitted_fields
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns an array with all fields that API will allow to use while creating a subject
|
33
|
+
# @note Override this method to add or remove fields that you don't want API to use for creating.
|
34
|
+
# @return [Array] of symbols representing attributes
|
35
|
+
# @used_in {#params_for_create}
|
36
|
+
# @use {#permitted_fields}
|
37
|
+
def permitted_fields_for_create
|
38
|
+
permitted_fields - [:id, :created_at, :updated_at]
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns an array with all fields that API will allow to use while updating a subject
|
42
|
+
# @note Override this method to add or remove fields that you don't want API to use for updating.
|
43
|
+
# @return [Array] of symbols representing attributes
|
44
|
+
# @used_in {#params_for_update}
|
45
|
+
# @use {#permitted_fields}
|
46
|
+
def permitted_fields_for_update
|
47
|
+
permitted_fields - [:id, :created_at, :updated_at]
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns an array with all fields that API will allow to use while sorting subjects
|
51
|
+
# @note Override this method to add or remove fields that you don't want API to use for sorting.
|
52
|
+
# @return [Array] of symbols representing attributes
|
53
|
+
# @used_in {#sort_params}
|
54
|
+
# @use {#permitted_fields}
|
55
|
+
def permitted_fields_for_sort
|
56
|
+
permitted_fields
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns an array with all fields that API will allow to use while filtering subjects by single value
|
60
|
+
# @note Override this method to add or remove fields that you don't want API to use for filtering by single value.
|
61
|
+
# If you want to change attributes that can be filtered by arrays of values check {#permitted_fields_for_filter_arrays}
|
62
|
+
# @return [Array] of symbols representing attributes
|
63
|
+
# @used_in {#permitted_fields_for_filter_arrays}
|
64
|
+
# @used_in {#permitted_fields_for_filter_with_arrays}
|
65
|
+
# @use {#permitted_fields}
|
66
|
+
def permitted_fields_for_filter
|
67
|
+
permitted_fields - [:created_at, :updated_at]
|
68
|
+
end
|
69
|
+
|
70
|
+
# Returns an array with all fields that API will allow to use while filtering subjects by array of values
|
71
|
+
# @note Override this method to add or remove fields that you don't want API to use for filtering by array of values.
|
72
|
+
# If you want to change attributes that can be filtered by single value check {#permitted_fields_for_filter}
|
73
|
+
# @return [Array] of symbols representing attributes
|
74
|
+
# @used_in {#permitted_fields_for_filter_with_arrays}
|
75
|
+
# @use {#permitted_fields_for_filter}
|
76
|
+
def permitted_fields_for_filter_arrays
|
77
|
+
permitted_fields_for_filter.map { |field| { field => [] } }
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns an array with all fields that API will allow to use while filtering subjects both by single values and by array of values
|
81
|
+
# @note To set fields that can be used check {#permitted_fields_for_filter} and {#permitted_fields_for_filter_arrays}
|
82
|
+
# @return [Array] of symbols representing attributes
|
83
|
+
# @used_in {#filter_params}
|
84
|
+
# @use {#permitted_fields_for_filter}
|
85
|
+
# @use {#permitted_fields_for_filter_arrays}
|
86
|
+
def permitted_fields_for_filter_with_arrays
|
87
|
+
permitted_fields_for_filter + permitted_fields_for_filter_arrays
|
88
|
+
end
|
89
|
+
|
90
|
+
# PARAMS
|
91
|
+
|
92
|
+
# Returns strong parameters which are used in creating action
|
93
|
+
# @note Override {#permitted_fields_for_create} to set allowed fields.
|
94
|
+
# Override {Subject#subject_model_sym} to change the root attrubute of params.
|
95
|
+
# @see http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters
|
96
|
+
# @used_in {Subject#create_subject}
|
97
|
+
# @use {Subject#subject_model_sym}
|
98
|
+
# @use {#permitted_fields_for_create}
|
99
|
+
def params_for_create
|
100
|
+
params.require(subject_model_sym).permit(permitted_fields_for_create)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Returns strong parameters which are used in updating action
|
104
|
+
# @note Override {#permitted_fields_for_update} to set allowed fields.
|
105
|
+
# Override {Subject#subject_model_sym} to change the root attrubute of params.
|
106
|
+
# @see http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters
|
107
|
+
# @used_in {Subject#update_subject}
|
108
|
+
# @use {Subject#subject_model_sym}
|
109
|
+
# @use {#permitted_fields_for_update}
|
110
|
+
def params_for_update
|
111
|
+
params.require(subject_model_sym).permit(permitted_fields_for_update)
|
112
|
+
end
|
113
|
+
|
114
|
+
# FILTERING
|
115
|
+
|
116
|
+
# Returns strong parameters which are used for filtering subjects
|
117
|
+
# @note Override {#permitted_fields_for_filter} and {permitted_fields_for_filter_arrays} to set allowed fields.
|
118
|
+
# @see http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters
|
119
|
+
# @used_in {Modificators#filter_subjects}
|
120
|
+
# @use {#permitted_fields_for_filter_with_arrays}
|
121
|
+
def filter_params
|
122
|
+
params[:filter] ? params.require(:filter).permit(permitted_fields_for_filter_with_arrays) : nil
|
123
|
+
end
|
124
|
+
|
125
|
+
# SORT
|
126
|
+
|
127
|
+
# Transforms a string like "-id,name" to a hash { id: :desc, name: :asc }
|
128
|
+
# @note Override {#permitted_fields_for_sort} to set allowed fields to sort.
|
129
|
+
# Override {#default_sort_params} to set default sort params.
|
130
|
+
# @used_in {Modificators#sort_subjects}
|
131
|
+
# @use {#permitted_fields_for_sort}
|
132
|
+
# @use {#default_sort_params}
|
133
|
+
def sort_params
|
134
|
+
sort_hash = nil
|
135
|
+
if params[:sort]
|
136
|
+
sort_array = params[:sort].split(',')
|
137
|
+
sort_array = sort_array.map do |field|
|
138
|
+
is_desc = field.split('-').count > 1
|
139
|
+
name = field.split('-').last
|
140
|
+
{ name: name.to_sym, is_desc: is_desc }
|
141
|
+
end
|
142
|
+
sort_array.select! do |field|
|
143
|
+
permitted_fields_for_sort.include? field[:name]
|
144
|
+
end
|
145
|
+
sort_array.each do |field|
|
146
|
+
sort_hash ||= {}
|
147
|
+
sort_hash[field[:name]] = field[:is_desc] ? :desc : :asc
|
148
|
+
end
|
149
|
+
end
|
150
|
+
sort_hash || default_sort_params
|
151
|
+
end
|
152
|
+
|
153
|
+
# Returns a hash with default sorting params
|
154
|
+
# @note Override {#permitted_fields_for_sort} to set allowed fields to sort.
|
155
|
+
# @see http://guides.rubyonrails.org/active_record_querying.html#ordering
|
156
|
+
# @used_in {#sort_params}
|
157
|
+
def default_sort_params
|
158
|
+
{id: :desc}
|
159
|
+
end
|
160
|
+
|
161
|
+
# PAGINATION
|
162
|
+
|
163
|
+
# Handles pagination params and return a hash like { page: 1, per_page: 10 }
|
164
|
+
# @note Override {#per_page_range} to set minimum and maximum per_page param.
|
165
|
+
# Override {#per_page_default} to set default per_page param.
|
166
|
+
# @used_in {Modificators#paginate_subjects}
|
167
|
+
# @use {#per_page_range}
|
168
|
+
# @use {#per_page_default}
|
169
|
+
def pagination_params
|
170
|
+
page = params[:page].try(:to_i) || 1
|
171
|
+
per_page = [per_page_range[:min], params[:per_page].try(:to_i) || per_page_default, per_page_range[:max]].sort[1]
|
172
|
+
return { page: page, per_page: per_page }
|
173
|
+
end
|
174
|
+
|
175
|
+
# Returns a hash minimum and maximum per_page param like { page: 1, per_page: 10 }
|
176
|
+
# @note Override {#per_page_default} to set default per_page param.
|
177
|
+
# @used_in {#pagination_params}
|
178
|
+
def per_page_range
|
179
|
+
{ min: 5, max: 100 }
|
180
|
+
end
|
181
|
+
|
182
|
+
# Returns a default per_page param
|
183
|
+
# @note Override {#per_page_range} to set minimum and maximum per_page param
|
184
|
+
# @used_in {#pagination_params}
|
185
|
+
def per_page_default
|
186
|
+
10
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module RestingPug
|
2
|
+
# Contains methods responsible for rendering response
|
3
|
+
# @used_in {Base.included}
|
4
|
+
module Render
|
5
|
+
protected
|
6
|
+
|
7
|
+
# Calls {#render_subject} if subject is valid and {#render_errors} otherwise
|
8
|
+
# @note Override {#render_subject} and {#render_errors} to change rendering behaviour
|
9
|
+
# @used_in {Chains#create_chain}
|
10
|
+
# @used_in {Chains#update_chain}
|
11
|
+
# @use {#render_subject}
|
12
|
+
# @use {#render_errors}
|
13
|
+
def decide_what_to_render
|
14
|
+
if @subject.valid?
|
15
|
+
render_subject
|
16
|
+
else
|
17
|
+
render_errors
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Renders json with a subject
|
22
|
+
# @note Override this method to add more complicated logic of rendering.
|
23
|
+
# Override {Subject#subject_model_sym} to change root attribute.
|
24
|
+
# Override {Params#permitted_fields_for_show} to change shown attributes.
|
25
|
+
# @used_in {#decide_what_to_render}
|
26
|
+
# @used_in {Chains#show_chain}
|
27
|
+
# @use {Subject#subject_model_sym}
|
28
|
+
# @use {Params#permitted_fields_for_show}
|
29
|
+
def render_subject
|
30
|
+
render json: { subject_model_sym => @subject.as_json(only: permitted_fields_for_show) }
|
31
|
+
end
|
32
|
+
|
33
|
+
# Renders json with subjects
|
34
|
+
# @note Override this method to add more complicated logic of rendering.
|
35
|
+
# Override {Subject#subject_model_sym_plural} to change root attribute.
|
36
|
+
# Override {Params#permitted_fields_for_show} to change shown attributes.
|
37
|
+
# @used_in {Chains#index_chain}
|
38
|
+
# @use {Subject#subject_model_sym_plural}
|
39
|
+
# @use {Params#permitted_fields_for_show}
|
40
|
+
def render_subjects
|
41
|
+
render json: { subject_model_sym_plural => @subjects.as_json(only: permitted_fields_for_show) }
|
42
|
+
end
|
43
|
+
|
44
|
+
# Renders empty response
|
45
|
+
# @note Override this method to add more complicated logic of rendering.
|
46
|
+
# @used_in {Subject#destroy_subject}
|
47
|
+
def render_nothing
|
48
|
+
render json: {}, status: 204
|
49
|
+
end
|
50
|
+
|
51
|
+
# Renders errors
|
52
|
+
# @note Override this method to add more complicated logic of rendering.
|
53
|
+
# @used_in {#decide_what_to_render}
|
54
|
+
def render_errors
|
55
|
+
render json: { errors: @subject.errors }, status: 422
|
56
|
+
end
|
57
|
+
|
58
|
+
# Renders error when required params are missing
|
59
|
+
# @note Override this method to add more complicated logic of rendering.
|
60
|
+
# @used_in {Base.included}
|
61
|
+
def render_param_missing
|
62
|
+
render json: { errors: { subject_model_sym => ['param is missing'] } }, status: 400
|
63
|
+
end
|
64
|
+
|
65
|
+
# Renders error when required params are missing
|
66
|
+
# @note Override this method to add more complicated logic of rendering.
|
67
|
+
# @used_in {Base.included}
|
68
|
+
def render_not_found
|
69
|
+
render json: {}, status: 404
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module RestingPug
|
2
|
+
# Defines everything related to subject basic operations(creation, updating etc)
|
3
|
+
# @used_in {Base.included}
|
4
|
+
module Subject
|
5
|
+
protected
|
6
|
+
|
7
|
+
# Gets a subject model from a controller class name
|
8
|
+
# @note Override this method if you want to use another model.
|
9
|
+
# @used_in {#subject_model_sym}
|
10
|
+
# @used_in {#subject_model_sym_plural}
|
11
|
+
# @used_in {#create_subject}
|
12
|
+
# @used_in {#fetch_subject}
|
13
|
+
# @used_in {#fetch_subjects}
|
14
|
+
# @used_in {Params#permitted_fields}
|
15
|
+
def subject_model
|
16
|
+
controller_name.classify.constantize
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns a symbol out of the subject model name
|
20
|
+
# @note Override this method to get another root for params and JSON responses.
|
21
|
+
# @use {#subject_model}
|
22
|
+
# @used_in {Params#params_for_create}
|
23
|
+
# @used_in {Params#params_for_update}
|
24
|
+
# @used_in {Render#render_subject}
|
25
|
+
# @used_in {Render#render_param_missing}
|
26
|
+
def subject_model_sym
|
27
|
+
subject_model.to_s.underscore.to_sym
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns a symbol out of the subject model name(plural)
|
31
|
+
# @note Override this method to get another root JSON response.
|
32
|
+
# @use {#subject_model}
|
33
|
+
# @used_in {Render#render_subjects}
|
34
|
+
def subject_model_sym_plural
|
35
|
+
subject_model.to_s.pluralize.underscore.to_sym
|
36
|
+
end
|
37
|
+
|
38
|
+
# Creates a subject
|
39
|
+
# @note Override this method to add some custom logic to creating process.
|
40
|
+
# @used_in {Chains#create_chain}
|
41
|
+
# @use {#subject_model}
|
42
|
+
# @use {Params#params_for_create}
|
43
|
+
def create_subject
|
44
|
+
@subject = subject_model.create(params_for_create)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Updates a subject
|
48
|
+
# @note Override this method to add some custom logic to updating process.
|
49
|
+
# @used_in {Chains#update_chain}
|
50
|
+
# @use {Params#params_for_update}
|
51
|
+
def update_subject
|
52
|
+
@subject.update(params_for_update)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Destroys a subject and render nothing or errors
|
56
|
+
# @note Override this method to add some custom logic to destroying process.
|
57
|
+
# @used_in {Chains#destroy_chain}
|
58
|
+
# @use {Render#render_nothing}
|
59
|
+
# @use {Render#render_errors}
|
60
|
+
def destroy_subject
|
61
|
+
if @subject.destroy
|
62
|
+
render_nothing
|
63
|
+
else
|
64
|
+
render_errors
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Finds a subject by id
|
69
|
+
# @note Override this method to add some custom logic to fetching process.
|
70
|
+
# @used_in {Chains#create_chain}
|
71
|
+
# @used_in {Chains#update_chain}
|
72
|
+
# @used_in {Chains#destroy_chain}
|
73
|
+
# @used_in {Chains#show_chain}
|
74
|
+
# @use {#subject_model}
|
75
|
+
def fetch_subject
|
76
|
+
@subject = subject_model.find(params[:id])
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns all subjects accessable for API
|
80
|
+
# @note Override this method to add some custom logic to fetching process.
|
81
|
+
# @used_in {Chains#index_chain}
|
82
|
+
# @use {#subject_model}
|
83
|
+
def fetch_subjects
|
84
|
+
@subjects = subject_model.all
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
metadata
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: resting_pug
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Slava Korolev
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-11-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: will_paginate
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rails
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5.1'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sqlite3
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec-rails
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.6'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.6'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: shoulda-matchers
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.1'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.1'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: factory_girl
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '4.8'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '4.8'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: faker
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.8'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.8'
|
111
|
+
description: Resting Pug allows you to create a JSON API with just adding one line
|
112
|
+
to your controller and fully customize it with overriding small and simple helper
|
113
|
+
methods.
|
114
|
+
email:
|
115
|
+
- korolvs@gmail.com
|
116
|
+
executables: []
|
117
|
+
extensions: []
|
118
|
+
extra_rdoc_files: []
|
119
|
+
files:
|
120
|
+
- MIT-LICENSE
|
121
|
+
- README.md
|
122
|
+
- Rakefile
|
123
|
+
- lib/resting_pug.rb
|
124
|
+
- lib/resting_pug/actions.rb
|
125
|
+
- lib/resting_pug/base.rb
|
126
|
+
- lib/resting_pug/chains.rb
|
127
|
+
- lib/resting_pug/modificators.rb
|
128
|
+
- lib/resting_pug/params.rb
|
129
|
+
- lib/resting_pug/render.rb
|
130
|
+
- lib/resting_pug/subject.rb
|
131
|
+
- lib/resting_pug/version.rb
|
132
|
+
- lib/tasks/resting_pug_tasks.rake
|
133
|
+
homepage: https://korolvs.github.io/resting_pug/
|
134
|
+
licenses:
|
135
|
+
- MIT
|
136
|
+
metadata: {}
|
137
|
+
post_install_message:
|
138
|
+
rdoc_options: []
|
139
|
+
require_paths:
|
140
|
+
- lib
|
141
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
requirements: []
|
152
|
+
rubyforge_project:
|
153
|
+
rubygems_version: 2.6.11
|
154
|
+
signing_key:
|
155
|
+
specification_version: 4
|
156
|
+
summary: A simple and fully customizable way to create an API in your Rails application.
|
157
|
+
test_files: []
|