belt 0.3.39 → 0.3.41

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: e529a712ad25eb12761d155d77b9a62f4342858c9b2272713edd0eef36ce7b6c
4
- data.tar.gz: e1e38c997a9bcfc0f454315915412cc4911cd832771cb389e8733b64d082fac9
3
+ metadata.gz: 1a7141bc9a4eff54bdc3b4c010d47f08c3917aed5072dfa2f976f83429c7c00e
4
+ data.tar.gz: 367789f59346408d662c87a955d22f95b7405d90f9711e819e216c58c155db17
5
5
  SHA512:
6
- metadata.gz: 4f2dbd95f0dfe51d250baeed09aa65d0704fbe783b67054b61f8eb6d46519c1fc0ebad6c641db6a5bd76fe75acd2f7a74a60abca16589b4e89da1dcb1d796bc2
7
- data.tar.gz: 462ba513dc663920b9cdd8af7fe12632d541c99f14234e8b43c4dd6e706de16995852a72781f38a572e3aa92f78111e304a924e92e8e03eb791a80209163df2b
6
+ metadata.gz: a5c9427efe1511e4f429ff46a7f14043a17b06c490915f62c535471ac984abcccda54801f765bf24e2b39e8a8f83b8939af53c69ad1414ae677cdf15d1943dd8
7
+ data.tar.gz: 4e90da0c8d2391bd3f7170acffeb083d04c3585092df86f413d4f3d2663386c21bac8ca6e833aecdea6883882569360d3b02e4239a17f52cf457fe65ed31b5d0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,58 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.41
4
+
5
+ ### Bug Fix
6
+
7
+ - **Fix API Gateway sibling path parameter conflict**: When a resource has nested
8
+ resources (a block), member routes (show, update, destroy) now use `{param_name}`
9
+ (e.g., `{project_id}`) instead of `{id}` to match the nested routes. This prevents
10
+ API Gateway from rejecting routes due to sibling path segments having different
11
+ parameter names.
12
+
13
+ Without nested resources (no block):
14
+ ```
15
+ GET /posts/{id}
16
+ PUT /posts/{id}
17
+ DELETE /posts/{id}
18
+ ```
19
+
20
+ With nested resources:
21
+ ```
22
+ GET /projects/{project_id}
23
+ PUT /projects/{project_id}
24
+ DELETE /projects/{project_id}
25
+ GET /projects/{project_id}/epics
26
+ GET /projects/{project_id}/epics/{id}
27
+ ```
28
+
29
+ This fixes the error: "Unable to create resource at path '...': A sibling ({id})
30
+ of this resource already has a variable path part".
31
+
32
+ ## 0.3.40
33
+
34
+ ### Breaking Change
35
+
36
+ - **Rails-style `{id}` for member routes**: Member routes (show, update, destroy)
37
+ now use `{id}` instead of `{singular_id}`. This matches Rails conventions where
38
+ the resource being operated on uses `:id`, and only parent resources use prefixed
39
+ names like `:project_id`.
40
+
41
+ Before:
42
+ ```
43
+ GET /projects/{project_id}
44
+ GET /projects/{project_id}/epics/{epic_id}
45
+ ```
46
+
47
+ After:
48
+ ```
49
+ GET /projects/{id}
50
+ GET /projects/{project_id}/epics/{id}
51
+ ```
52
+
53
+ Parent resources in nested routes still use `{singular_id}` (e.g., `{project_id}`,
54
+ `{epic_id}` when they are parents of nested resources).
55
+
3
56
  ## 0.3.39
4
57
 
5
58
  ### Enhancement
@@ -251,7 +251,8 @@ module Belt
251
251
  end
252
252
  end
253
253
 
254
- def add_nested_resource_routes(resource_name, param_name, resource_options, actions)
254
+ def add_nested_resource_routes(resource_name, _param_name, resource_options, actions)
255
+ # Member routes (show/update/destroy) use {id}, not {singular_id} — Rails convention
255
256
  if actions.include?(:index)
256
257
  @gateway.send(:add_route, :get, "#{@prefix}/#{resource_name}",
257
258
  resolve_request_model_for(resource_options, :index))
@@ -261,16 +262,16 @@ module Belt
261
262
  resolve_request_model_for(resource_options, :create))
262
263
  end
263
264
  if actions.include?(:show)
264
- @gateway.send(:add_route, :get, "#{@prefix}/#{resource_name}/{#{param_name}}",
265
+ @gateway.send(:add_route, :get, "#{@prefix}/#{resource_name}/{id}",
265
266
  resolve_request_model_for(resource_options, :show))
266
267
  end
267
268
  if actions.include?(:update)
268
- @gateway.send(:add_route, :put, "#{@prefix}/#{resource_name}/{#{param_name}}",
269
+ @gateway.send(:add_route, :put, "#{@prefix}/#{resource_name}/{id}",
269
270
  resolve_request_model_for(resource_options, :update))
270
271
  end
271
272
  return unless actions.include?(:destroy)
272
273
 
273
- @gateway.send(:add_route, :delete, "#{@prefix}/#{resource_name}/{#{param_name}}",
274
+ @gateway.send(:add_route, :delete, "#{@prefix}/#{resource_name}/{id}",
274
275
  resolve_request_model_for(resource_options, :destroy))
275
276
  end
276
277
 
@@ -415,9 +416,12 @@ module Belt
415
416
  resource_options = options.merge(route_type: :resources)
416
417
  actions = determine_actions(options)
417
418
 
418
- add_resource_routes(resource_name, param_name, resource_options, actions)
419
+ # When there are nested resources, use {param_name} for member routes to avoid
420
+ # API Gateway sibling path parameter conflicts. Without nested resources, use {id}.
421
+ has_nested = block_given?
422
+ add_resource_routes(resource_name, param_name, resource_options, actions, use_param_name: has_nested)
419
423
 
420
- return unless block_given?
424
+ return unless has_nested
421
425
 
422
426
  collection_prefix = "/#{resource_name}"
423
427
  member_prefix = "/#{resource_name}/{#{param_name}}"
@@ -496,7 +500,11 @@ module Belt
496
500
  options.merge(tables: [resource_name.to_sym])
497
501
  end
498
502
 
499
- def add_resource_routes(resource_name, param_name, resource_options, actions)
503
+ def add_resource_routes(resource_name, param_name, resource_options, actions, use_param_name: false)
504
+ # Member routes (show/update/destroy) use {id} by default (Rails convention).
505
+ # When nested resources exist (use_param_name: true), use {param_name} instead
506
+ # to avoid API Gateway sibling path parameter conflicts.
507
+ member_param = use_param_name ? param_name : 'id'
500
508
  if actions.include?(:index)
501
509
  add_route(:get, "/#{resource_name}",
502
510
  resolve_request_model_for(resource_options, :index))
@@ -506,16 +514,16 @@ module Belt
506
514
  resolve_request_model_for(resource_options, :create))
507
515
  end
508
516
  if actions.include?(:show)
509
- add_route(:get, "/#{resource_name}/{#{param_name}}",
517
+ add_route(:get, "/#{resource_name}/{#{member_param}}",
510
518
  resolve_request_model_for(resource_options, :show))
511
519
  end
512
520
  if actions.include?(:update)
513
- add_route(:put, "/#{resource_name}/{#{param_name}}",
521
+ add_route(:put, "/#{resource_name}/{#{member_param}}",
514
522
  resolve_request_model_for(resource_options, :update))
515
523
  end
516
524
  return unless actions.include?(:destroy)
517
525
 
518
- add_route(:delete, "/#{resource_name}/{#{param_name}}", resolve_request_model_for(resource_options, :destroy))
526
+ add_route(:delete, "/#{resource_name}/{#{member_param}}", resolve_request_model_for(resource_options, :destroy))
519
527
  end
520
528
 
521
529
  def resolve_request_model_for(options, action)
@@ -797,7 +805,11 @@ module Belt
797
805
  end
798
806
  end
799
807
 
800
- def add_scoped_resource_routes(resource_name, param_name, resource_options, actions)
808
+ def add_scoped_resource_routes(resource_name, param_name, resource_options, actions, use_param_name: false)
809
+ # Member routes (show/update/destroy) use {id} by default (Rails convention).
810
+ # When nested resources exist (use_param_name: true), use {param_name} instead
811
+ # to avoid API Gateway sibling path parameter conflicts.
812
+ member_param = use_param_name ? param_name : 'id'
801
813
  if actions.include?(:index)
802
814
  @gateway.send(:add_route, :get, build_path("/#{resource_name}"),
803
815
  resolve_request_model_for(resource_options, :index))
@@ -807,16 +819,16 @@ module Belt
807
819
  resolve_request_model_for(resource_options, :create))
808
820
  end
809
821
  if actions.include?(:show)
810
- @gateway.send(:add_route, :get, build_path("/#{resource_name}/{#{param_name}}"),
822
+ @gateway.send(:add_route, :get, build_path("/#{resource_name}/{#{member_param}}"),
811
823
  resolve_request_model_for(resource_options, :show))
812
824
  end
813
825
  if actions.include?(:update)
814
- @gateway.send(:add_route, :put, build_path("/#{resource_name}/{#{param_name}}"),
826
+ @gateway.send(:add_route, :put, build_path("/#{resource_name}/{#{member_param}}"),
815
827
  resolve_request_model_for(resource_options, :update))
816
828
  end
817
829
  return unless actions.include?(:destroy)
818
830
 
819
- @gateway.send(:add_route, :delete, build_path("/#{resource_name}/{#{param_name}}"),
831
+ @gateway.send(:add_route, :delete, build_path("/#{resource_name}/{#{member_param}}"),
820
832
  resolve_request_model_for(resource_options, :destroy))
821
833
  end
822
834
 
@@ -839,7 +851,10 @@ module Belt
839
851
  resource_options = options.merge(route_type: :resources, controller: controller)
840
852
  actions = determine_scoped_actions(options)
841
853
 
842
- add_scoped_resource_routes(resource_name, param_name, resource_options, actions)
854
+ # When there are nested resources, use {param_name} for member routes to avoid
855
+ # API Gateway sibling path parameter conflicts. Without nested resources, use {id}.
856
+ has_nested = !block.nil?
857
+ add_scoped_resource_routes(resource_name, param_name, resource_options, actions, use_param_name: has_nested)
843
858
  build_nested_resource_block(resource_name, param_name, options, controller, &block) if block
844
859
  end
845
860
 
data/lib/belt/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Belt
4
- VERSION = '0.3.39'
4
+ VERSION = '0.3.41'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: belt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.39
4
+ version: 0.3.41
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stowzilla