deep_unrest 0.1.0 → 0.1.1

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
  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