rest_rails 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b126ebf0d0ee509d040b57b6ff35dd7bb3ab837c09e499159f369a8d56df21ee
4
- data.tar.gz: 91cbf7f438cfa373ba2c9d61f2d1f44f8e3eda84da4244dae1da01e384d898e7
3
+ metadata.gz: 652e20dd610f1f6647f5d4dadac3d16a6d782bc0dc9765993d8bd064eb571e4e
4
+ data.tar.gz: 4fcfb8bef731b3e1067f033d1d62eee2f31478e7f737673cc1100d222f491a69
5
5
  SHA512:
6
- metadata.gz: e6ca726a3603a6ed9ce3ceec63379e266a64c993677c063c9c693940e95d08105b311a9becfdc4380f12ad411e29088f1d7b58462afa0bc3810be8b29ae99483
7
- data.tar.gz: dc96c4175867bfc18c1fe059421e0613ee3ab0145ba7910953e62fe5d0ce8595096928ee869d448473ee70487f76679564298c45248b0d0ca1697bf9df09aa9c
6
+ metadata.gz: 8427c35cfdf814c694802321f3d4b8f808f38ba8cd1b92957cc70102d1c4b56331237688213d2348fbed2c712667162091b28a558e17fee28f103b02efeeb6e9
7
+ data.tar.gz: 2740b7604869ed36bf0fc594e385412b33c5bb4e3b4517cd69daba52f6fb40dc4fa63acc27409dd2b4f5fa30034978abb774fdaa922087aa01f8aa4c85112dfb
data/README.md CHANGED
@@ -3,10 +3,33 @@ Rails Plugin for quick intelligent API Creation by Tuitu Technology Solutions
3
3
 
4
4
  ## How To Start
5
5
 
6
+ ### Step 1: Basic Setup
6
7
  1. Add To Gemfile: `gem 'rest_rails'`
7
8
  2. Bundle Install: `bundle install`
8
9
  3. Install RestRails: `rails g rest_rails:install`
9
- 4. Modify initializer and/or mounted route.
10
+
11
+ ### Step 2: Change Mounted Path (optional)
12
+ 1. Make sure the line `mount RestRails::Engine => '/api/v1', as: 'rest'` is at the *bottom* of your routes. (This will prevent RestRails from taking over any custom API routing you might do)
13
+ 2. Change '/api/v1' to whatever naming structure you would like to prepend REST API routes.
14
+
15
+ ### Step 3: Whitelist Permitted Columns (optional)
16
+ 1. For better security, it is strongly recommended to setup the initializer to whitelist your columns.
17
+
18
+ Here is an example on how to whitelist columns for a sample database w/ three tables: articles, comments, users.
19
+ In this example, we only want the API to allow REST API endpoints for articles and comments, but not users.
20
+
21
+ *Note: table_names are keys. Acceptable values include: (:all, :none, or an Array of column_names)*
22
+
23
+ ```
24
+ RestRails.configure do |config|
25
+ # ...
26
+ config.permit = {
27
+ articles: :all,
28
+ users: :none,
29
+ comments: [:content]
30
+ }
31
+ end
32
+ ```
10
33
 
11
34
  ## The Basics
12
35
 
@@ -52,9 +75,9 @@ destroy | DELETE | `/api/v1/comments/:id` | destroy a
52
75
  fetch_column | GET | `/api/v1/comments/:id/article_id` | fetch article_id of comment
53
76
  fetch_column | GET | `/api/v1/comments/:id/content` | fetch content of comment
54
77
 
55
- # HOW TO USE THE REST API
78
+ # Using the REST API
56
79
 
57
- ## INDEX: GET '/table_name'
80
+ ## Index
58
81
  GET '/articles' will return a JSON response as follows:
59
82
  ```
60
83
  {
@@ -110,7 +133,7 @@ article\[description\]\[\] | *Array* | article\[description\]\[\]=SomeDescript
110
133
  article[content] | *String* | article[content]=Some+Content | Will match articles with contents same as the value.
111
134
  article\[content\]\[\] | *Array* | article\[content\]\[\]=SomeContent&article\[content\]\[\]=SomeOtherContent | Will match articles with content of 'SomeContent' OR 'SomeOtherContent'
112
135
 
113
- ## SHOW: GET '/table_name/:id'
136
+ ## Show
114
137
  GET '/articles/1' will return a JSON response as follows:
115
138
  ```
116
139
  {
@@ -139,7 +162,7 @@ GET '/articles/1' will return a JSON response as follows:
139
162
  }
140
163
  ```
141
164
 
142
- ## CREATE: POST '/table_name'
165
+ ## Create
143
166
 
144
167
  The create paths enforce Rails **strong params**. So only properly structured requests will be allowed.
145
168
  POST '/articles' can accept a payload in the following structure:
@@ -185,7 +208,7 @@ If successful (and passes your ActiveRecord validations), the response will be a
185
208
  }
186
209
  ```
187
210
 
188
- ## UPDATE: PATCH '/table_name/:id'
211
+ ## Update
189
212
 
190
213
  The update paths enforce Rails **strong params**. So only properly structured requests will be allowed.
191
214
  PATCH '/articles/1' can accept a payload in the following structure (with one or more columns to be updated):
@@ -230,7 +253,7 @@ If successful (and passes your ActiveRecord validations), the response will be a
230
253
  }
231
254
  ```
232
255
 
233
- ## DESTROY: DELETE '/table_name'
256
+ ## Destroy
234
257
 
235
258
  DELETE '/articles/1' only needs the ID number.
236
259
 
@@ -245,7 +268,7 @@ If successful (and passes your ActiveRecord validations), the response will be a
245
268
 
246
269
  **Note:** If you are using activestorage, the destroy process will also automatically destroy attachments from your bucket.
247
270
 
248
- ## FETCH_COLUMN: GET '/table_name/:id/:column_name'
271
+ ## Fetch Column
249
272
 
250
273
  GET '/articles/1/title'
251
274
 
@@ -290,19 +313,21 @@ And for has_many_attached:
290
313
  }
291
314
  ```
292
315
 
293
- # ACTIVESTORAGE ATTACHMENTS
316
+ # Activestorage Attachments
294
317
 
295
318
  For activestorage attachment support, the following two routes are added to models using activestorage:
296
319
 
297
320
  `/table_name/:id/attach/:attachment_name` and `/table_name/:id/unattach/:attachment_id`
298
321
 
299
- ## ATTACH: POST '/table_name/:id/attach/:attachment_name'
322
+ ## Attach
300
323
 
301
324
  The routes generated for the rest API are based on the naming provided in your ActiveRecord model when using activestorage.
302
325
 
303
326
  - Supports both has_one_attached & has_many_attached.
304
327
 
305
- In the articles example above, this would be: "/api/v1/articles/attach/feature_image"
328
+ In the articles example above, this would be:
329
+
330
+ POST "/api/v1/articles/attach/feature_image"
306
331
 
307
332
  The payload structure in this case needs only to be:
308
333
  ```
@@ -320,7 +345,9 @@ If successful, the response will be as follows:
320
345
  }
321
346
  ```
322
347
 
323
- ## UNATTACH: DELETE '/table_name/:id/unattach/:attachment_id'
348
+ ## Unattach
349
+
350
+ DELETE '/table_name/:id/unattach/:attachment_id'
324
351
 
325
352
  *\* Note, Response will fail if the attachment_id provided does not belong to the object.*
326
353
 
@@ -334,10 +361,10 @@ If successful, the response will be as follows:
334
361
  ```
335
362
 
336
363
 
337
-
338
-
339
364
  ## Contribution
340
365
  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
366
  - Support different popular attachment gems.
343
367
  - Add Locale fetching based on page-routes.
368
+ - Add standarized testing rspecs.
369
+ - Add support for switching activestorage sources
370
+ - Add support to allow user to provide any before_actions wanted.
@@ -3,7 +3,8 @@ module RestRails
3
3
  class DataController < ::ApplicationController
4
4
  include ApplicationHelper
5
5
  skip_before_action :verify_authenticity_token
6
- before_action :set_model, only: [:index, :show, :create, :update, :destroy, :fetch_column, :attach, :unattach]
6
+ before_action :verify_table_permissions!, only: [:create, :update, :destroy, :attach, :unattach]
7
+ before_action :set_model
7
8
  before_action :set_object, only: [:show, :update, :destroy, :fetch_column, :attach, :unattach]
8
9
 
9
10
  def index
@@ -36,7 +37,7 @@ module RestRails
36
37
  end
37
38
 
38
39
  def create
39
- @object = @empty_obj(model_params)
40
+ @object = @model.new(model_params)
40
41
 
41
42
  attach_files
42
43
  if @object.save
@@ -99,6 +100,7 @@ module RestRails
99
100
  # Take the tablename, and make the Model of the relative table_name
100
101
  @model = model_for(params[:table_name])
101
102
  @empty_obj = @model.new
103
+ p @empty_obj
102
104
  end
103
105
 
104
106
  def set_object
@@ -112,8 +114,6 @@ module RestRails
112
114
  return {} if params[mn].blank?
113
115
  # MAKE LIST OF THINGS TO PERMIT:
114
116
  arr = @model.attribute_names.map(&:to_sym)
115
- arr.delete(:created_at)
116
- arr.delete(:updated_at)
117
117
 
118
118
  # allow arrays for all columns for flexible where queries
119
119
  arr += arr.map do |attr|
@@ -159,25 +159,19 @@ module RestRails
159
159
  end
160
160
 
161
161
  def permitted_columns
162
- @columns = @model.attribute_names.map(&:to_sym)
162
+ p @empty_obj
163
+ @columns = columns_for(@empty_obj)
163
164
  @columns.delete(:id)
164
165
  @columns.delete(:created_at)
165
166
  @columns.delete(:updated_at)
166
167
 
167
- @columns.map! do |attr|
168
- new_val = permit_array?(attr) ? {attr=>[]} : attr
169
- new_val
170
- end
171
- permitted_attachments if RestRails.active_storage_attachments
172
- end
173
-
174
- def permitted_attachments
175
- file_set = attachments_for(@empty_obj)
176
- file_set += file_set.select{|x| permit_array?(x)}.map do |attr|
168
+ @columns += @columns.select{|x| permit_array?(x)}.map do |attr|
177
169
  {attr=>[]}
178
170
  end
171
+ end
179
172
 
180
- @columns = @columns + file_set
173
+ def verify_table_permissions!
174
+ verify_permitted!(params[:table_name].to_sym)
181
175
  end
182
176
  end
183
177
  end
@@ -58,8 +58,13 @@ module RestRails
58
58
  end
59
59
 
60
60
  def columns_for(ar_object)
61
- cols = ar_object.class.attribute_names.map(&:to_sym)
62
- cols += attachments_for(ar_object)
61
+ table = ar_object.class.table_name.to_sym
62
+ cols = ar_object.class.column_names.map(&:to_sym)
63
+ cols += attachments_for(ar_object) if RestRails.active_storage_attachments
64
+
65
+ return cols if RestRails.permit == :all || RestRails.permit[table] == :all
66
+
67
+ cols.select{|x| RestRails.permit[table].include?(x) }
63
68
  end
64
69
 
65
70
  # ==========================================================================
@@ -76,5 +81,13 @@ module RestRails
76
81
  # Take the tablename, and make the Model of the relative table_name
77
82
  table_name.classify.constantize # "users" => User
78
83
  end
84
+
85
+ def verify_permitted!(table)
86
+ if [:none, nil].include?(RestRails.permit[table])
87
+ raise RestRails::Error.new "NOT PERMITTED. Must add table to whitelisted params."
88
+ elsif !RestRails.permit.is_a?(Hash) && (RestRails.permit != :all)
89
+ raise RestRails::Error.new "RestRails initializer permit is not valid!"
90
+ end
91
+ end
79
92
  end
80
93
  end
@@ -4,6 +4,18 @@ RestRails.configure do |config|
4
4
  # set debug to true if you want to see loud errors in the server logs.
5
5
  config.debug = false
6
6
 
7
+ # ===============================================================
8
+ # IMPORTANT!
9
+ # Setup whitelist permissions for what db columns can be
10
+ # modified by the REST API
11
+ # ===============================================================
12
+ # config.permit = {
13
+ # users: :none,
14
+ # table_name: :all,
15
+ # other_table: [:col1, :col2, :col3]
16
+ # }
17
+
18
+ # ===============================================================
7
19
  # if you are using devise or another authentication system and want to
8
20
  # enforce the before_action `authenticate_user!`
9
21
  #
@@ -1,3 +1,3 @@
1
1
  module RestRails
2
- VERSION = '0.8.0'
2
+ VERSION = '0.9.0'
3
3
  end
data/lib/rest_rails.rb CHANGED
@@ -3,6 +3,7 @@ require "rest_rails/error"
3
3
 
4
4
  module RestRails
5
5
  mattr_accessor :debug, default: false
6
+ mattr_accessor :permit, default: :all
6
7
  mattr_accessor :authenticatable, default: false
7
8
  mattr_accessor :active_storage_attachments, default: true
8
9
  mattr_accessor :production_domain, default: nil
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rest_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergio Rivas