deep_unrest 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 16cfa1baac8c2a73223981948c63a5573202ea22
4
- data.tar.gz: 31f808c464f4b7c10470728d8a8f731afb2deca1
3
+ metadata.gz: f251e8aee5961ebae0a57cedf79dc6ce424dc2d4
4
+ data.tar.gz: a62e10cd9dfdc0f4e83dc31bef8d4bea68f5b479
5
5
  SHA512:
6
- metadata.gz: 4592d731550af2ed983b9e520d3794abce76c706b372d95381942325b980a4359495a5b6ce14b281bbd733dbd3513f79f6a9276f1027668ed21377108bd91589
7
- data.tar.gz: 420cf01968544730f6f1842986e2c9000dc1204c259d043a11b73e62c31346c81e61ed0b917e84134df94e4caeebd7b8e01a886c4fb5f6afa62eb91b78252175
6
+ metadata.gz: e009d9471f9661b9c178fe3f0f3fc1cbf936cfeda8c009ce24354e69dc289d56e67886433480dbb7b846a9d7c70b2b7d0f0d38612e4dbf247924e1b8b6272136
7
+ data.tar.gz: 6e577f6e6c8fb2ab6f5a5cf29d70d3255d52c9ab31644e124525acb8d497fe21212d1b5de918154d31dd7e88631c46463202bdb3c84425747e37a37d08cc0439
data/README.md CHANGED
@@ -1,15 +1,21 @@
1
- # Deep UnREST
1
+ <img src="/docs/img/logo.jpg" width="100%">
2
2
 
3
3
  [![CircleCI](https://circleci.com/gh/graveflex/deep_unrest.svg?style=svg)](https://circleci.com/gh/graveflex/deep_unrest)
4
4
  [![Test Coverage](https://codeclimate.com/repos/591cc05fbd15c32ce10014b4/badges/36013471f0d2c4c6f875/coverage.svg)](https://codeclimate.com/repos/591cc05fbd15c32ce10014b4/coverage)
5
5
  [![Code Climate](https://codeclimate.com/repos/591cc05fbd15c32ce10014b4/badges/36013471f0d2c4c6f875/gpa.svg)](https://codeclimate.com/repos/591cc05fbd15c32ce10014b4/feed)
6
6
  [![Issue Count](https://codeclimate.com/repos/591cc05fbd15c32ce10014b4/badges/36013471f0d2c4c6f875/issue_count.svg)](https://codeclimate.com/repos/591cc05fbd15c32ce10014b4/feed)
7
7
 
8
- <img src="/docs/img/logo.png" width="100%">
8
+ ## Goals
9
9
 
10
- Perform updates on deeply nested resources as well as bulk operations.
10
+ * Allow updates and deletions of deeply nested resources
11
+ * Allow bulk updates and deletions
12
+ * Perform authorization on all affected resources
13
+ * Control which params each user is allowed to update for each resource
14
+ * Provide clear errors to the client
11
15
 
12
- ## Goals
16
+ ## Caveats
17
+
18
+ * This approach is not RESTful
13
19
 
14
20
  ## Installation
15
21
  Add this line to your application's Gemfile:
@@ -49,12 +55,16 @@ $ bundle
49
55
  # config.get_user = proc { current_admin || current_user }
50
56
 
51
57
  # stategy that will be used to authorize the current user for each resource
52
- self.authorization_strategy = DeepUnrest::Authorization::PunditStrategy
58
+ config.authorization_strategy = DeepUnrest::Authorization::PunditStrategy
53
59
  end
54
60
  ```
55
61
 
56
62
  ## Usage
57
63
 
64
+ For the following examples, consider this data model:
65
+
66
+ <img src="/docs/img/example-setup.jpg" width="100%">
67
+
58
68
  ### Example 1 - Simple Update:
59
69
  Update attributes on a single `Submission` with id `123`
60
70
 
@@ -103,7 +113,7 @@ within their policy scope.
103
113
  ```
104
114
 
105
115
  ##### 405 Response:
106
- This error will occur when a is allowed to update a resource, but not
116
+ This error will occur when a user is allowed to update a resource, but not
107
117
  specified attributes of that resource.
108
118
 
109
119
  ```javascript
@@ -161,6 +171,7 @@ resource. The temporary ID should be surrounded in brackets (`[]`).
161
171
  ```javascript
162
172
  // PATCH /deep_unrest/update
163
173
  {
174
+ redirect: '/submissions/[1]',
164
175
  data: [
165
176
  {
166
177
  path: 'submissions[1]',
@@ -172,6 +183,24 @@ resource. The temporary ID should be surrounded in brackets (`[]`).
172
183
  }
173
184
  ```
174
185
 
186
+ ##### 200 Response:
187
+ When a temp id (`[id]`) is present in the redirect url, the temp id will be
188
+ replaced with the id given to the new resource.
189
+
190
+ Using the example above, assuming that the `Submission` at path
191
+ `submissions[1]` was given the id `123`, the redirect request param of
192
+ `/submissions/[1]` will be replaced with `/submissions/123`.
193
+
194
+ ```javascript
195
+ {
196
+ id: 123,
197
+ type: 'submissions',
198
+ attributes: {
199
+ name: 'testing'
200
+ }
201
+ }
202
+ ```
203
+
175
204
  ##### Create Errors:
176
205
  All errors regarding the new resource will use the temp ID as the path to the error.
177
206
 
@@ -192,7 +221,7 @@ example will perform the following operations:
192
221
 
193
222
  * Change the `name` column of `Submission` with id `123` to `test`
194
223
  * Change the `value` column of `Answer` with id `1` to `yes`
195
- * Create a new `Answer` with a value of `No` using temp ID `[1]`
224
+ * Create a new `Answer` with a value of `no` using temp ID `[1]`
196
225
  * Delete the `Answer` with id `2`
197
226
 
198
227
  These operations will be performed within a single `ActiveRecord` transaction.
@@ -253,7 +282,7 @@ limited to the current user's allowed scope.
253
282
  ```
254
283
 
255
284
  ### Example 6 - Bulk Delete
256
- The following example will delete every submission.
285
+ The following example will delete every `Submission`.
257
286
 
258
287
  When using an authorization strategy, the scope of the bulk delete will be
259
288
  limited to the current user's allowed scope.
@@ -9,10 +9,10 @@ module DeepUnrest
9
9
 
10
10
  def update
11
11
  redirect = allowed_params[:redirect]
12
- DeepUnrest.perform_update(allowed_params[:data],
13
- current_user)
12
+ redirect_replace = DeepUnrest.perform_update(allowed_params[:data],
13
+ current_user)
14
14
  if redirect
15
- redirect_to redirect
15
+ redirect_to redirect_replace.call(redirect)
16
16
  else
17
17
  render json: {}, status: 200
18
18
  end
@@ -1,3 +1,3 @@
1
1
  module DeepUnrest
2
- VERSION = '0.1.0'
2
+ VERSION = '0.1.1'
3
3
  end
data/lib/deep_unrest.rb CHANGED
@@ -197,18 +197,14 @@ module DeepUnrest
197
197
  cursor
198
198
  end
199
199
 
200
- def self.get_mutation_cursor(memo, cursor, addr, type, id, destroy)
200
+ def self.get_mutation_cursor(memo, cursor, addr, type, id, temp_id, scope_type)
201
201
  if memo
202
202
  cursor[addr] = [{}]
203
203
  next_cursor = cursor[addr][0]
204
204
  else
205
+ method = scope_type == :show ? :update : scope_type
205
206
  cursor = {}
206
207
  type_sym = type.to_sym
207
- if destroy
208
- method = id ? :update : :destroy_all
209
- else
210
- method = id ? :update : :update_all
211
- end
212
208
  klass = to_class(type)
213
209
  body = {}
214
210
  body[klass.primary_key.to_sym] = id if id
@@ -221,6 +217,7 @@ module DeepUnrest
221
217
  method: method,
222
218
  body: body
223
219
  }
220
+ cursor[type_sym][:operations][id][method][:temp_id] = temp_id if temp_id
224
221
  memo = cursor
225
222
  next_cursor = cursor[type_sym][:operations][id][method][:body]
226
223
  end
@@ -238,8 +235,16 @@ module DeepUnrest
238
235
  type, id_str = rest.shift
239
236
  addr = to_update_body_key(type)
240
237
  id = parse_id(id_str)
238
+ scope_type = get_scope_type(id_str, rest.blank?, op[:destroy])
239
+ temp_id = scope_type == :create ? id_str : nil
241
240
 
242
- memo, next_cursor = get_mutation_cursor(memo, cursor, addr, type, id, op[:destroy])
241
+ memo, next_cursor = get_mutation_cursor(memo,
242
+ cursor,
243
+ addr,
244
+ type,
245
+ id,
246
+ temp_id,
247
+ scope_type)
243
248
 
244
249
  next_cursor[:id] = id if id
245
250
  build_mutation_fragment(op, user, rest, memo, next_cursor, type)
@@ -255,22 +260,28 @@ module DeepUnrest
255
260
  mutation.map do |_, item|
256
261
  item[:operations].map do |id, ops|
257
262
  ops.map do |_, action|
258
- case action[:method]
259
- when :update_all
260
- DeepUnrest.authorization_strategy
261
- .get_authorized_scope(user, item[:klass])
262
- .update(action[:body])
263
- nil
264
- when :destroy_all
265
- DeepUnrest.authorization_strategy
266
- .get_authorized_scope(user, item[:klass])
267
- .destroy_all
268
- nil
269
- when :update
270
- item[:klass].update(id, action[:body])
271
- when :create
272
- item[:klass].create(action[:body])
263
+ record = case action[:method]
264
+ when :update_all
265
+ DeepUnrest.authorization_strategy
266
+ .get_authorized_scope(user, item[:klass])
267
+ .update(action[:body])
268
+ nil
269
+ when :destroy_all
270
+ DeepUnrest.authorization_strategy
271
+ .get_authorized_scope(user, item[:klass])
272
+ .destroy_all
273
+ nil
274
+ when :update
275
+ item[:klass].update(id, action[:body])
276
+ when :create
277
+ item[:klass].create(action[:body])
278
+ end
279
+ result = { record: record }
280
+ if action[:temp_id]
281
+ result[:temp_ids] = {}
282
+ result[:temp_ids][action[:temp_id]] = record.id
273
283
  end
284
+ result
274
285
  end
275
286
  end
276
287
  end
@@ -307,6 +318,19 @@ module DeepUnrest
307
318
  end.flatten
308
319
  end
309
320
 
321
+ def self.build_redirect_regex(replacements)
322
+ replacements ||= []
323
+
324
+ replace_ops = replacements.map do |k, v|
325
+ proc { |str| str.sub(k.to_s, v.to_s) }
326
+ end
327
+
328
+ proc do |str|
329
+ replace_ops.each { |op| str = op.call(str) }
330
+ str
331
+ end
332
+ end
333
+
310
334
  def self.perform_update(params, user)
311
335
  # identify requested scope(s)
312
336
  scopes = collect_all_scopes(params)
@@ -321,13 +345,18 @@ module DeepUnrest
321
345
  results = mutate(mutations, user).flatten
322
346
 
323
347
  # check results for errors
324
- errors = results.compact
348
+ errors = results.map { |res| res[:record] }
349
+ .compact
325
350
  .map(&:errors)
326
351
  .map(&:messages)
327
352
  .reject(&:empty?)
328
353
  .compact
329
-
330
- return if errors.empty?
354
+ if errors.empty?
355
+ temp_ids = results.map { |res| res[:temp_ids] }
356
+ .compact
357
+ .each_with_object({}) { |item, mem| mem.merge!(item) }
358
+ return build_redirect_regex(temp_ids)
359
+ end
331
360
 
332
361
  # map errors to their sources
333
362
  formatted_errors = { errors: map_errors_to_param_keys(scopes, errors) }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deep_unrest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lynn Hurley
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-05-17 00:00:00.000000000 Z
11
+ date: 2017-05-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails