rest_rails 0.1.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +334 -7
- data/app/controllers/rest_rails/data_controller.rb +24 -14
- data/app/helpers/rest_rails/application_helper.rb +28 -7
- data/config/routes.rb +8 -10
- data/lib/generators/rest_rails/USAGE +2 -0
- data/lib/generators/rest_rails/install_generator.rb +24 -0
- data/lib/generators/rest_rails/templates/README +27 -0
- data/lib/generators/rest_rails/templates/rest_rails.rb +29 -0
- data/lib/rest_rails/version.rb +1 -1
- data/lib/rest_rails.rb +3 -1
- metadata +8 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b126ebf0d0ee509d040b57b6ff35dd7bb3ab837c09e499159f369a8d56df21ee
|
4
|
+
data.tar.gz: 91cbf7f438cfa373ba2c9d61f2d1f44f8e3eda84da4244dae1da01e384d898e7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6ca726a3603a6ed9ce3ceec63379e266a64c993677c063c9c693940e95d08105b311a9becfdc4380f12ad411e29088f1d7b58462afa0bc3810be8b29ae99483
|
7
|
+
data.tar.gz: dc96c4175867bfc18c1fe059421e0613ee3ab0145ba7910953e62fe5d0ce8595096928ee869d448473ee70487f76679564298c45248b0d0ca1697bf9df09aa9c
|
data/README.md
CHANGED
@@ -1,16 +1,343 @@
|
|
1
1
|
# RestRails
|
2
2
|
Rails Plugin for quick intelligent API Creation by Tuitu Technology Solutions
|
3
3
|
|
4
|
-
## How To
|
4
|
+
## How To Start
|
5
5
|
|
6
|
-
Add To Gemfile:
|
6
|
+
1. Add To Gemfile: `gem 'rest_rails'`
|
7
|
+
2. Bundle Install: `bundle install`
|
8
|
+
3. Install RestRails: `rails g rest_rails:install`
|
9
|
+
4. Modify initializer and/or mounted route.
|
7
10
|
|
8
|
-
|
11
|
+
## The Basics
|
12
|
+
|
13
|
+
RestRails will automatically create a base API for all standard CRUD actions.
|
14
|
+
Just one line of code to implement a powerful REST API.
|
15
|
+
|
16
|
+
For Example's sake, let's take the following schema:
|
17
|
+
|
18
|
+
- **articles:** *title, description, content*
|
19
|
+
- **comments:** *article_id, content*
|
20
|
+
|
21
|
+
Further more, as per activestorage convention, **Article** *has_one_attached :feature_image* & *has_many_attached :content_images*
|
22
|
+
|
23
|
+
Let's say we mount RestRails at `/api/v1`, the Following routes are included for articles:
|
24
|
+
|
25
|
+
### Articles
|
26
|
+
|
27
|
+
REST action | method | route | notes
|
28
|
+
------------ | ------ | -------------------------------------------- | ----------------------
|
29
|
+
index | GET | `/api/v1/articles` | index paginated by 100
|
30
|
+
show | GET | `/api/v1/articles/:id` | show for one article
|
31
|
+
create | POST | `/api/v1/articles` | create new article
|
32
|
+
update | GET | `/api/v1/articles/:id` | update an article
|
33
|
+
destroy | DELETE | `/api/v1/articles/:id` | destroy an article
|
34
|
+
fetch_column | GET | `/api/v1/articles/:id/title` | fetch title of article
|
35
|
+
fetch_column | GET | `/api/v1/articles/:id/description` | fetch description of article
|
36
|
+
fetch_column | GET | `/api/v1/articles/:id/content` | fetch content of article
|
37
|
+
attach | POST | `/api/v1/articles/:id/attach/feature_image` | attach file to feature_image
|
38
|
+
attach | POST | `/api/v1/articles/:id/attach/content_images` | attach file to content_images
|
39
|
+
|
40
|
+
|
41
|
+
And the following for comments:
|
42
|
+
|
43
|
+
### Comments
|
44
|
+
|
45
|
+
REST action | method | route | notes
|
46
|
+
------------ | ------ | -------------------------------------------- | ----------------------
|
47
|
+
index | GET | `/api/v1/comments` | index paginated by 100
|
48
|
+
show | GET | `/api/v1/comments/:id` | show for one comment
|
49
|
+
create | POST | `/api/v1/comments` | create new comment
|
50
|
+
update | GET | `/api/v1/comments/:id` | update an comment
|
51
|
+
destroy | DELETE | `/api/v1/comments/:id` | destroy an comment
|
52
|
+
fetch_column | GET | `/api/v1/comments/:id/article_id` | fetch article_id of comment
|
53
|
+
fetch_column | GET | `/api/v1/comments/:id/content` | fetch content of comment
|
54
|
+
|
55
|
+
# HOW TO USE THE REST API
|
56
|
+
|
57
|
+
## INDEX: GET '/table_name'
|
58
|
+
GET '/articles' will return a JSON response as follows:
|
59
|
+
```
|
60
|
+
{
|
61
|
+
"code": 200,
|
62
|
+
"objects": [
|
63
|
+
{
|
64
|
+
"id": 1,
|
65
|
+
"created_at": "2019-08-27T08:22:19.357Z",
|
66
|
+
"updated_at": "2019-08-27T08:22:19.499Z",
|
67
|
+
"title": "Discourse on Dystopian Non Fiction",
|
68
|
+
"description": "This is an abstract description used to mislead readers into clicking on the article and take a deeper read.",
|
69
|
+
"content": "Wow, the reader actually clicked! Now let me brainwash him with this heavily opinionated article based on a myriad of unverified sources with the credibility of a personified M&M's...",
|
70
|
+
"feature_image": {
|
71
|
+
"attachment_id": 1,
|
72
|
+
"url": "http://localhost:3000/rails/active_storage/blobs/eyJfcmFpbHMiOnsib--f573ab9452c272881fb/jopmqH0.jpg"
|
73
|
+
},
|
74
|
+
"content_images": [
|
75
|
+
{
|
76
|
+
"attachment_id": 3,
|
77
|
+
"url": "http://localhost:3000/rails/active_storage/blobs/sjfioadifo-8fdjsfaj/fjso.jpg"
|
78
|
+
}, {
|
79
|
+
"attachment_id": 12,
|
80
|
+
"url": "http://localhost:3000/rails/active_storage/blobs/fjiods--k0f09fs/jfdsjk.jpg"
|
81
|
+
}
|
82
|
+
]
|
83
|
+
},
|
84
|
+
{...},
|
85
|
+
{...},
|
86
|
+
...
|
87
|
+
],
|
88
|
+
"count": 100,
|
89
|
+
"total": 1300
|
90
|
+
}
|
91
|
+
```
|
92
|
+
|
93
|
+
The index REST API is by *default* paginated by 100. To go through pages, add the following params to the GET path:
|
94
|
+
|
95
|
+
`page=<number>`
|
96
|
+
|
97
|
+
ex: '/api/v1/articles?page=2'
|
98
|
+
|
99
|
+
Models can also be filtered by a very basic WHERE query param structure.
|
100
|
+
|
101
|
+
For Article, the index API point can receive the following paramters:
|
102
|
+
|
103
|
+
param | type | example | notes
|
104
|
+
-------------------------- | --------- | ---------------- | --------------------
|
105
|
+
page | *Integer* | page=2 | Will paginate by 100 per page.
|
106
|
+
article[title] | *String* | article[title]=Some+Title | Will match articles with titles same as the value.
|
107
|
+
article\[title\]\[\] | *Array* | article\[title\]\[\]=SomeTitle&article\[title\]\[\]=SomeOtherTitle | Will match articles with title of 'SomeTitle' OR 'SomeOtherTitle'
|
108
|
+
article[description] | *String* | article[description]=Some+Description | Will match articles with descriptions same as the value.
|
109
|
+
article\[description\]\[\] | *Array* | article\[description\]\[\]=SomeDescription&article\[description\]\[\]=SomeOtherDescription | Will match articles with description of 'SomeDescription' OR 'SomeOtherDescription'
|
110
|
+
article[content] | *String* | article[content]=Some+Content | Will match articles with contents same as the value.
|
111
|
+
article\[content\]\[\] | *Array* | article\[content\]\[\]=SomeContent&article\[content\]\[\]=SomeOtherContent | Will match articles with content of 'SomeContent' OR 'SomeOtherContent'
|
112
|
+
|
113
|
+
## SHOW: GET '/table_name/:id'
|
114
|
+
GET '/articles/1' will return a JSON response as follows:
|
115
|
+
```
|
116
|
+
{
|
117
|
+
"code": 200,
|
118
|
+
"object": {
|
119
|
+
"id": 1,
|
120
|
+
"created_at": "2019-08-27T08:22:19.357Z",
|
121
|
+
"updated_at": "2019-08-27T08:22:19.499Z",
|
122
|
+
"title": "Discourse on Dystopian Non Fiction",
|
123
|
+
"description": "This is an abstract description used to mislead readers into clicking on the article and take a deeper read.",
|
124
|
+
"content": "Wow, the reader actually clicked! Now let me brainwash him with this heavily opinionated article based on a myriad of unverified sources with the credibility of a personified M&M's...",
|
125
|
+
"feature_image": {
|
126
|
+
"attachment_id": 1,
|
127
|
+
"url": "http://localhost:3000/rails/active_storage/blobs/eyJfcmFpbHMiOnsib--f573ab9452c272881fb/jopmqH0.jpg"
|
128
|
+
},
|
129
|
+
"content_images": [
|
130
|
+
{
|
131
|
+
"attachment_id": 3,
|
132
|
+
"url": "http://localhost:3000/rails/active_storage/blobs/sjfioadifo-8fdjsfaj/fjso.jpg"
|
133
|
+
}, {
|
134
|
+
"attachment_id": 12,
|
135
|
+
"url": "http://localhost:3000/rails/active_storage/blobs/fjiods--k0f09fs/jfdsjk.jpg"
|
136
|
+
}
|
137
|
+
]
|
138
|
+
}
|
139
|
+
}
|
140
|
+
```
|
141
|
+
|
142
|
+
## CREATE: POST '/table_name'
|
143
|
+
|
144
|
+
The create paths enforce Rails **strong params**. So only properly structured requests will be allowed.
|
145
|
+
POST '/articles' can accept a payload in the following structure:
|
146
|
+
|
147
|
+
```
|
148
|
+
{
|
149
|
+
"article" {
|
150
|
+
"title": "Discourse on Dystopian Non Fiction",
|
151
|
+
"description": "This is an abstract description used to mislead readers into clicking on the article and take a deeper read.",
|
152
|
+
"content": "Wow, the reader actually clicked! Now let me brainwash him with this heavily opinionated article based on a myriad of unverified sources with the credibility of a personified M&M's..."
|
153
|
+
}
|
154
|
+
}
|
155
|
+
```
|
156
|
+
|
157
|
+
If successful (and passes your ActiveRecord validations), the response will be as follows:
|
158
|
+
|
159
|
+
```
|
160
|
+
{
|
161
|
+
"code": 200,
|
162
|
+
"msg": "success",
|
163
|
+
"object": {
|
164
|
+
"id": 1,
|
165
|
+
"created_at": "2019-08-27T08:22:19.357Z",
|
166
|
+
"updated_at": "2019-08-27T08:22:19.357Z",
|
167
|
+
"title": "Discourse on Dystopian Non Fiction",
|
168
|
+
"description": "This is an abstract description used to mislead readers into clicking on the article and take a deeper read.",
|
169
|
+
"content": "Wow, the reader actually clicked! Now let me brainwash him with this heavily opinionated article based on a myriad of unverified sources with the credibility of a personified M&M's...",
|
170
|
+
"feature_image": null,
|
171
|
+
"content_images": []
|
172
|
+
}
|
173
|
+
}
|
174
|
+
```
|
175
|
+
|
176
|
+
**Note:** If you are using forms to submit data w/ attachments via activestorage, you can also add attachments to the payload sent, as long as it matches the naming of your activestorage attachment, and the form submission content-type is multipart/form_data.
|
177
|
+
|
178
|
+
```
|
179
|
+
{
|
180
|
+
"article" {
|
181
|
+
"title": "Discourse on Dystopian Non Fiction",
|
182
|
+
"description": "This is an abstract description used to mislead readers into clicking on the article and take a deeper read.",
|
183
|
+
"feature_image": <uploaded_file>
|
184
|
+
}
|
185
|
+
}
|
186
|
+
```
|
187
|
+
|
188
|
+
## UPDATE: PATCH '/table_name/:id'
|
189
|
+
|
190
|
+
The update paths enforce Rails **strong params**. So only properly structured requests will be allowed.
|
191
|
+
PATCH '/articles/1' can accept a payload in the following structure (with one or more columns to be updated):
|
192
|
+
|
193
|
+
```
|
194
|
+
{
|
195
|
+
"article" {
|
196
|
+
"title": "Discourse on Dystopian Non Fiction",
|
197
|
+
"description": "This is an abstract description used to mislead readers into clicking on the article and take a deeper read.",
|
198
|
+
"content": "Wow, the reader actually clicked! Now let me brainwash him with this heavily opinionated article based on a myriad of unverified sources with the credibility of a personified M&M's..."
|
199
|
+
}
|
200
|
+
}
|
201
|
+
```
|
202
|
+
|
203
|
+
If successful (and passes your ActiveRecord validations), the response will be as follows:
|
204
|
+
|
205
|
+
```
|
206
|
+
{
|
207
|
+
"code": 200,
|
208
|
+
"msg": "success",
|
209
|
+
"object": {
|
210
|
+
"id": 1,
|
211
|
+
"created_at": "2019-08-27T08:22:19.357Z",
|
212
|
+
"updated_at": "2019-08-27T08:22:19.357Z",
|
213
|
+
"title": "Discourse on Dystopian Non Fiction",
|
214
|
+
"description": "This is an abstract description used to mislead readers into clicking on the article and take a deeper read.",
|
215
|
+
"content": "Wow, the reader actually clicked! Now let me brainwash him with this heavily opinionated article based on a myriad of unverified sources with the credibility of a personified M&M's...",
|
216
|
+
"feature_image": null,
|
217
|
+
"content_images": []
|
218
|
+
}
|
219
|
+
}
|
220
|
+
```
|
221
|
+
|
222
|
+
**Note:** If you are using forms to submit data w/ attachments via activestorage, you can also add attachments to the payload sent, as long as it matches the naming of your activestorage attachment, and the form submission content-type is multipart/form_data.
|
223
|
+
|
224
|
+
```
|
225
|
+
{
|
226
|
+
"article" {
|
227
|
+
"title": "Discourse on Dystopian Non Fiction",
|
228
|
+
"feature_image": <uploaded_file>
|
229
|
+
}
|
230
|
+
}
|
231
|
+
```
|
232
|
+
|
233
|
+
## DESTROY: DELETE '/table_name'
|
234
|
+
|
235
|
+
DELETE '/articles/1' only needs the ID number.
|
236
|
+
|
237
|
+
If successful (and passes your ActiveRecord validations), the response will be as follows:
|
9
238
|
|
10
239
|
```
|
11
|
-
|
240
|
+
{
|
241
|
+
"code": 200,
|
242
|
+
"msg": "success"
|
243
|
+
}
|
12
244
|
```
|
13
|
-
## TODO
|
14
245
|
|
15
|
-
|
16
|
-
|
246
|
+
**Note:** If you are using activestorage, the destroy process will also automatically destroy attachments from your bucket.
|
247
|
+
|
248
|
+
## FETCH_COLUMN: GET '/table_name/:id/:column_name'
|
249
|
+
|
250
|
+
GET '/articles/1/title'
|
251
|
+
|
252
|
+
If column exists, the response will be as follows:
|
253
|
+
|
254
|
+
```
|
255
|
+
{
|
256
|
+
"code": 200,
|
257
|
+
"msg": "success",
|
258
|
+
"value": "Discourse on Dystopian Non Fiction"
|
259
|
+
}
|
260
|
+
```
|
261
|
+
|
262
|
+
**Note:** If you are using activestorage, you will return the following for has_one_attached:
|
263
|
+
|
264
|
+
```
|
265
|
+
{
|
266
|
+
"code": 200,
|
267
|
+
"msg": "success",
|
268
|
+
"value": {
|
269
|
+
"attachment_id": 1,
|
270
|
+
"url": "http://localhost:3000/rails/active_storage/blobs/eyJfcmFpbHMiOnsib--f573ab9452c272881fb/jopmqH0.jpg"
|
271
|
+
}
|
272
|
+
}
|
273
|
+
```
|
274
|
+
And for has_many_attached:
|
275
|
+
|
276
|
+
```
|
277
|
+
{
|
278
|
+
"code": 200,
|
279
|
+
"msg": "success",
|
280
|
+
"value": [
|
281
|
+
{
|
282
|
+
"attachment_id": 3,
|
283
|
+
"url": "http://localhost:3000/rails/active_storage/blobs/sjfioadifo-8fdjsfaj/fjso.jpg"
|
284
|
+
},
|
285
|
+
{
|
286
|
+
"attachment_id": 12,
|
287
|
+
"url": "http://localhost:3000/rails/active_storage/blobs/fjiods--k0f09fs/jfdsjk.jpg"
|
288
|
+
}
|
289
|
+
]
|
290
|
+
}
|
291
|
+
```
|
292
|
+
|
293
|
+
# ACTIVESTORAGE ATTACHMENTS
|
294
|
+
|
295
|
+
For activestorage attachment support, the following two routes are added to models using activestorage:
|
296
|
+
|
297
|
+
`/table_name/:id/attach/:attachment_name` and `/table_name/:id/unattach/:attachment_id`
|
298
|
+
|
299
|
+
## ATTACH: POST '/table_name/:id/attach/:attachment_name'
|
300
|
+
|
301
|
+
The routes generated for the rest API are based on the naming provided in your ActiveRecord model when using activestorage.
|
302
|
+
|
303
|
+
- Supports both has_one_attached & has_many_attached.
|
304
|
+
|
305
|
+
In the articles example above, this would be: "/api/v1/articles/attach/feature_image"
|
306
|
+
|
307
|
+
The payload structure in this case needs only to be:
|
308
|
+
```
|
309
|
+
{
|
310
|
+
attachment: <file_uploaded>
|
311
|
+
}
|
312
|
+
```
|
313
|
+
|
314
|
+
If successful, the response will be as follows:
|
315
|
+
|
316
|
+
```
|
317
|
+
{
|
318
|
+
"code": 200,
|
319
|
+
"msg": "success"
|
320
|
+
}
|
321
|
+
```
|
322
|
+
|
323
|
+
## UNATTACH: DELETE '/table_name/:id/unattach/:attachment_id'
|
324
|
+
|
325
|
+
*\* Note, Response will fail if the attachment_id provided does not belong to the object.*
|
326
|
+
|
327
|
+
If successful, the response will be as follows:
|
328
|
+
|
329
|
+
```
|
330
|
+
{
|
331
|
+
"code": 200,
|
332
|
+
"msg": "success"
|
333
|
+
}
|
334
|
+
```
|
335
|
+
|
336
|
+
|
337
|
+
|
338
|
+
|
339
|
+
## Contribution
|
340
|
+
Here are some features in need of development.
|
341
|
+
- Add way to "protect columns" (i.e. exclude columns from permitted params for model's update/create API points).
|
342
|
+
- Support different popular attachment gems.
|
343
|
+
- Add Locale fetching based on page-routes.
|
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'json'
|
2
2
|
module RestRails
|
3
|
-
class DataController <
|
4
|
-
include
|
3
|
+
class DataController < ::ApplicationController
|
4
|
+
include ApplicationHelper
|
5
|
+
skip_before_action :verify_authenticity_token
|
5
6
|
before_action :set_model, only: [:index, :show, :create, :update, :destroy, :fetch_column, :attach, :unattach]
|
6
7
|
before_action :set_object, only: [:show, :update, :destroy, :fetch_column, :attach, :unattach]
|
7
8
|
|
@@ -13,22 +14,29 @@ module RestRails
|
|
13
14
|
|
14
15
|
if params[:page].blank? || (params[:page].to_i < 1)
|
15
16
|
if @objects.empty?
|
16
|
-
|
17
|
+
@objects = []
|
17
18
|
else
|
18
|
-
|
19
|
+
@objects = @objects[0].reject{|x|x.nil?}.map{|x| standardize_json(x) }
|
19
20
|
end
|
20
21
|
else
|
21
22
|
i = params[:page].to_i - 1
|
22
|
-
|
23
|
+
objs = @objects[i]
|
24
|
+
if objs.nil?
|
25
|
+
@objects = []
|
26
|
+
else
|
27
|
+
@objects = objs.reject{|x|x.nil?}.map{|x| standardize_json(x) }
|
28
|
+
end
|
23
29
|
end
|
30
|
+
|
31
|
+
render json: {code: 200, objects: @objects, count: @objects.count, total: @model.count}
|
24
32
|
end
|
25
33
|
|
26
34
|
def show
|
27
|
-
render json: {code: 200
|
35
|
+
render json: {code: 200, object: standardize_json(@object)}
|
28
36
|
end
|
29
37
|
|
30
38
|
def create
|
31
|
-
@object = @
|
39
|
+
@object = @empty_obj(model_params)
|
32
40
|
|
33
41
|
attach_files
|
34
42
|
if @object.save
|
@@ -56,18 +64,19 @@ module RestRails
|
|
56
64
|
end
|
57
65
|
|
58
66
|
def fetch_column
|
59
|
-
raise RestRails::Error.new "Column '#{params[:column]}' does not exist for #{params[:table_name]} table!" unless @
|
67
|
+
raise RestRails::Error.new "Column '#{params[:column]}' does not exist for #{params[:table_name]} table!" unless columns_for(@object).include?(params[:column])
|
60
68
|
|
61
|
-
|
69
|
+
col_value = @object.public_send(params[:column])
|
70
|
+
render json: {code: 200, msg: "success", value: prepare_column(col_value)}
|
62
71
|
end
|
63
72
|
|
64
73
|
def attach
|
65
74
|
# post '/:table_name/:id/attach/:attachment_name' => 'data#attach'
|
66
75
|
raise RestRails::Error.new "No Attached file!" unless params[:attachment].is_a?(ActionDispatch::Http::UploadedFile)
|
67
|
-
raise RestRails::Error.new "Attachment '#{params[:attachment_name]}' does not exist for #{params[:table_name]} table!" unless attachments_for(@
|
76
|
+
raise RestRails::Error.new "Attachment '#{params[:attachment_name]}' does not exist for #{params[:table_name]} table!" unless attachments_for(@empty_obj).include?(params[:attachment_name].to_sym)
|
68
77
|
|
69
78
|
@object.public_send(params[:attachment_name].to_sym).attach(params[:attachment])
|
70
|
-
render json: {code: 200, msg: "
|
79
|
+
render json: {code: 200, msg: "success"}
|
71
80
|
end
|
72
81
|
|
73
82
|
def unattach
|
@@ -89,6 +98,7 @@ module RestRails
|
|
89
98
|
|
90
99
|
# Take the tablename, and make the Model of the relative table_name
|
91
100
|
@model = model_for(params[:table_name])
|
101
|
+
@empty_obj = @model.new
|
92
102
|
end
|
93
103
|
|
94
104
|
def set_object
|
@@ -116,7 +126,7 @@ module RestRails
|
|
116
126
|
# BASED ON ACTIVE STORAGE
|
117
127
|
mn = @model.model_name.singular.to_sym # /users => user
|
118
128
|
#
|
119
|
-
file_set = attachments_for(@
|
129
|
+
file_set = attachments_for(@empty_obj)
|
120
130
|
file_set.each do |fs|
|
121
131
|
next if params[mn].blank? || params[mn][fs].blank?
|
122
132
|
attachment = params[mn][fs]
|
@@ -145,7 +155,7 @@ module RestRails
|
|
145
155
|
|
146
156
|
def permit_array?(attr)
|
147
157
|
permitable_classes = [ActiveStorage::Attached::Many, Array]
|
148
|
-
permitable_classes.include?(@
|
158
|
+
permitable_classes.include?(@empty_obj.send(attr).class)
|
149
159
|
end
|
150
160
|
|
151
161
|
def permitted_columns
|
@@ -162,7 +172,7 @@ module RestRails
|
|
162
172
|
end
|
163
173
|
|
164
174
|
def permitted_attachments
|
165
|
-
file_set = attachments_for(@
|
175
|
+
file_set = attachments_for(@empty_obj)
|
166
176
|
file_set += file_set.select{|x| permit_array?(x)}.map do |attr|
|
167
177
|
{attr=>[]}
|
168
178
|
end
|
@@ -14,24 +14,40 @@ module RestRails
|
|
14
14
|
h = {}
|
15
15
|
attachment_types = attachments_for(ar_object)
|
16
16
|
attachment_types.each do |att|
|
17
|
-
attached =
|
18
|
-
|
19
|
-
h[att] =
|
17
|
+
attached = ar_object.public_send(att)
|
18
|
+
next if attached.nil?
|
19
|
+
h[att] = prepare_attachment(attached)
|
20
20
|
end
|
21
21
|
return h
|
22
22
|
end
|
23
23
|
|
24
|
+
def attachment_hash(attached)
|
25
|
+
{attachment_id: attached.id, url: blob_link(attached)}
|
26
|
+
end
|
27
|
+
|
24
28
|
def blob_link(x)
|
25
|
-
|
29
|
+
if Rails.env == "production"
|
30
|
+
host = RestRails.production_domain || ""
|
31
|
+
else
|
32
|
+
host = RestRails.development_domain || "http://localhost:3000"
|
33
|
+
end
|
26
34
|
Rails.application.routes.url_helpers.rails_blob_url(x, host: host)
|
27
35
|
end
|
28
36
|
|
29
|
-
def
|
37
|
+
def prepare_column(col_value)
|
38
|
+
if [ActiveStorage::Attached::Many, ActiveStorage::Attached::One].include?(col_value.class)
|
39
|
+
return prepare_attachment(col_value)
|
40
|
+
else
|
41
|
+
return col_value
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def prepare_attachment(attached)
|
30
46
|
if attached.class == ActiveStorage::Attached::Many
|
31
|
-
return attached.map{|x|
|
47
|
+
return attached.map{|x| attachment_hash(x) }
|
32
48
|
elsif attached.class == ActiveStorage::Attached::One
|
33
49
|
x = attached.attachment
|
34
|
-
return
|
50
|
+
return attachment_hash(x) unless x.nil?
|
35
51
|
end
|
36
52
|
end
|
37
53
|
|
@@ -41,6 +57,11 @@ module RestRails
|
|
41
57
|
attach_meths.map{|x| x[14..-1].to_sym}
|
42
58
|
end
|
43
59
|
|
60
|
+
def columns_for(ar_object)
|
61
|
+
cols = ar_object.class.attribute_names.map(&:to_sym)
|
62
|
+
cols += attachments_for(ar_object)
|
63
|
+
end
|
64
|
+
|
44
65
|
# ==========================================================================
|
45
66
|
# OTHER HELPERS
|
46
67
|
# ==========================================================================
|
data/config/routes.rb
CHANGED
@@ -1,15 +1,13 @@
|
|
1
1
|
RestRails::Engine.routes.draw do
|
2
|
-
|
3
|
-
|
4
|
-
post '/:table_name' => 'data#create'
|
2
|
+
get '/:table_name' => 'data#index', as: 'data_index'
|
3
|
+
post '/:table_name' => 'data#create'
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
get '/:table_name/:id' => 'data#show', as: 'data_show'
|
6
|
+
patch '/:table_name/:id' => 'data#update'
|
7
|
+
delete '/:table_name/:id' => 'data#destroy', as: 'data_destroy'
|
9
8
|
|
10
|
-
|
11
|
-
|
9
|
+
post '/:table_name/:id/attach/:attachment_name' => 'data#attach'
|
10
|
+
delete '/:table_name/:id/unattach/:attachment_id' => 'data#unattach'
|
12
11
|
|
13
|
-
|
14
|
-
end
|
12
|
+
get '/:table_name/:id/:column' => 'data#fetch_column'
|
15
13
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RestRails
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
namespace "rest_rails:install"
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
# argument :name, :type => :string, :default => "en"
|
9
|
+
def basic_setup
|
10
|
+
# Setup Initializer
|
11
|
+
template "rest_rails.rb", "config/initializers/rest_rails.rb"
|
12
|
+
end
|
13
|
+
def setup_routes
|
14
|
+
route "mount RestRails::Engine => '/api/v1', as: 'rest'"
|
15
|
+
route "# For more information, check out the gem repo: https://github.com/sergio-rivas/rest-rails"
|
16
|
+
route "# Note: Make sure RestRails engine is at the BOTTOM of routes"
|
17
|
+
route "# RestRails standard REST API for all models"
|
18
|
+
end
|
19
|
+
def completed
|
20
|
+
readme "README"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
========================================================================
|
2
|
+
|
3
|
+
_-====-__-======-__-========-_____-============-__
|
4
|
+
_( All aboard! Now hopping on... _)
|
5
|
+
OO( ╦═╗┌─┐┌─┐┌┬┐╦═╗┌─┐┬┬ ┌─┐ )_
|
6
|
+
0 (_ ╠╦╝├┤ └─┐ │ ╠╦╝├─┤││ └─┐ _)
|
7
|
+
o0 (_ ╩╚═└─┘└─┘ ┴ ╩╚═┴ ┴┴┴─┘└─┘ _)
|
8
|
+
o '=-___-===-_____-========-___________-===-dwb-='
|
9
|
+
.o _________
|
10
|
+
. ______ ______________ | | _____
|
11
|
+
_()_||__|| ________ | by | |_________| __||___||__
|
12
|
+
( R.R. | | | | Tuitu | __Y______00_| |_ _|
|
13
|
+
/-OO----OO""="OO--OO"="OO--------OO"="OO-------OO"="OO-------OO"=P
|
14
|
+
|
15
|
+
========================================================================
|
16
|
+
|
17
|
+
Next Steps:
|
18
|
+
|
19
|
+
1) Modify the initializer in /config/initializers/rest_rails.rb
|
20
|
+
2) Read the documentation at: https://github.com/sergio-rivas/rest-rails
|
21
|
+
3) experiment and have fun!
|
22
|
+
|
23
|
+
---*Bonus*---
|
24
|
+
make sure to send feedback and feature requests!
|
25
|
+
And issues too, if you encounter strange errors.
|
26
|
+
|
27
|
+
Pull Requests welcome~
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Here's the configuration setup for RestRails!
|
2
|
+
|
3
|
+
RestRails.configure do |config|
|
4
|
+
# set debug to true if you want to see loud errors in the server logs.
|
5
|
+
config.debug = false
|
6
|
+
|
7
|
+
# if you are using devise or another authentication system and want to
|
8
|
+
# enforce the before_action `authenticate_user!`
|
9
|
+
#
|
10
|
+
# Note: take a look at `simple_token_authentication` or `tiddle` gems to setup
|
11
|
+
# token-based authentication for devise.
|
12
|
+
config.authenticatable = false
|
13
|
+
|
14
|
+
|
15
|
+
# ===============================================
|
16
|
+
# ACTIVE STORAGE SETTINGS FOR ATTACHMENTS
|
17
|
+
# ===============================================
|
18
|
+
# to enable REST attachments via active storage
|
19
|
+
config.active_storage_attachments = false
|
20
|
+
|
21
|
+
# to setup domains to attach to urls returned from activestorage blob_url.
|
22
|
+
# if used for WEB, you can simply put "/"
|
23
|
+
# if using for Native Apps, or WeChat/AliPay Mini Programs,
|
24
|
+
# you should have this be the domain of your API host. e.g.: 'https://api.fakeurl.com'
|
25
|
+
config.production_domain = nil
|
26
|
+
|
27
|
+
# Set development domain if needed.
|
28
|
+
config.development_domain = "http://localhost:3000"
|
29
|
+
end
|
data/lib/rest_rails/version.rb
CHANGED
data/lib/rest_rails.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
require "rest_rails/engine"
|
2
|
+
require "rest_rails/error"
|
2
3
|
|
3
4
|
module RestRails
|
4
5
|
mattr_accessor :debug, default: false
|
5
6
|
mattr_accessor :authenticatable, default: false
|
6
7
|
mattr_accessor :active_storage_attachments, default: true
|
7
|
-
mattr_accessor :
|
8
|
+
mattr_accessor :production_domain, default: nil
|
9
|
+
mattr_accessor :development_domain, default: 'localhost:3000'
|
8
10
|
|
9
11
|
def self.configure
|
10
12
|
yield self
|
metadata
CHANGED
@@ -1,35 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rest_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sergio Rivas
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-12-
|
11
|
+
date: 2019-12-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 6.0.2
|
20
17
|
- - ">="
|
21
18
|
- !ruby/object:Gem::Version
|
22
|
-
version:
|
19
|
+
version: 5.2.1
|
23
20
|
type: :runtime
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
26
23
|
requirements:
|
27
|
-
- - "~>"
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: 6.0.2
|
30
24
|
- - ">="
|
31
25
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
26
|
+
version: 5.2.1
|
33
27
|
- !ruby/object:Gem::Dependency
|
34
28
|
name: sqlite3
|
35
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -60,6 +54,10 @@ files:
|
|
60
54
|
- app/controllers/rest_rails/data_controller.rb
|
61
55
|
- app/helpers/rest_rails/application_helper.rb
|
62
56
|
- config/routes.rb
|
57
|
+
- lib/generators/rest_rails/USAGE
|
58
|
+
- lib/generators/rest_rails/install_generator.rb
|
59
|
+
- lib/generators/rest_rails/templates/README
|
60
|
+
- lib/generators/rest_rails/templates/rest_rails.rb
|
63
61
|
- lib/rest_rails.rb
|
64
62
|
- lib/rest_rails/engine.rb
|
65
63
|
- lib/rest_rails/error.rb
|