Skip to content

Commit 8cdcf06

Browse files
committed
Do not overwrite route_param with a regular one if they share same name
1 parent c6ad84a commit 8cdcf06

File tree

7 files changed

+177
-1
lines changed

7 files changed

+177
-1
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
* [#2387](https://github.com/ruby-grape/grape/pull/2387): Fix rubygems version within workflows - [@ericproulx](https://github.com/ericproulx).
2929
* [#2405](https://github.com/ruby-grape/grape/pull/2405): Fix edge workflow - [@ericproulx](https://github.com/ericproulx).
3030
* [#2414](https://github.com/ruby-grape/grape/pull/2414): Fix Rack::Lint missing content-type - [@ericproulx](https://github.com/ericproulx).
31+
* [#2378](https://github.com/ruby-grape/grape/pull/2378): Do not overwrite `route_param` with a regular one if they share same name - [@arg](https://github.com/arg).
3132
* Your contribution here.
3233

3334
### 2.0.0 (2023/11/11)

README.md

+30
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
- [Include Parent Namespaces](#include-parent-namespaces)
4040
- [Include Missing](#include-missing)
4141
- [Evaluate Given](#evaluate-given)
42+
- [Parameter Precedence](#parameter-precedence)
4243
- [Parameter Validation and Coercion](#parameter-validation-and-coercion)
4344
- [Supported Parameter Types](#supported-parameter-types)
4445
- [Integer/Fixnum and Coercions](#integerfixnum-and-coercions)
@@ -1198,6 +1199,35 @@ curl -X POST -H "Content-Type: application/json" localhost:9292/child -d '{"chil
11981199
}
11991200
````
12001201

1202+
### Parameter Precedence
1203+
1204+
Using `route_param` takes higher precedence over a regular parameter defined with same name:
1205+
1206+
```ruby
1207+
params do
1208+
requires :foo, type: String
1209+
end
1210+
route_param :foo do
1211+
get do
1212+
{ value: params[:foo] }
1213+
end
1214+
end
1215+
```
1216+
1217+
**Request**
1218+
1219+
```bash
1220+
curl -X POST -H "Content-Type: application/json" localhost:9292/bar -d '{"foo": "baz"}'
1221+
```
1222+
1223+
**Response**
1224+
1225+
```json
1226+
{
1227+
"value": "bar"
1228+
}
1229+
```
1230+
12011231
## Parameter Validation and Coercion
12021232

12031233
You can define validations and coercion options for your parameters using a `params` block.

UPGRADING.md

+53
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,59 @@ The `rack_response` method has been deprecated and the `error_response` method h
99

1010
See [#2414](https://github.com/ruby-grape/grape/pull/2414) for more information.
1111

12+
#### Change in parameters precedence
13+
14+
When using together with `Grape::Extensions::Hash::ParamBuilder`, `route_param` takes higher precedence over a regular parameter defined with same name, which now matches the default param builder behavior.
15+
16+
This was a regression introduced by [#2326](https://github.com/ruby-grape/grape/pull/2326) in Grape v1.8.0.
17+
18+
```ruby
19+
grape.configure do |config|
20+
config.param_builder = Grape::Extensions::Hash::ParamBuilder
21+
end
22+
23+
params do
24+
requires :foo, type: String
25+
end
26+
route_param :foo do
27+
get do
28+
{ value: params[:foo] }
29+
end
30+
end
31+
```
32+
33+
Request:
34+
35+
```bash
36+
curl -X POST -H "Content-Type: application/json" localhost:9292/bar -d '{"foo": "baz"}'
37+
```
38+
39+
Response prior to v1.8.0:
40+
41+
```json
42+
{
43+
"value": "bar"
44+
}
45+
```
46+
47+
v1.8.0..v2.0.0:
48+
49+
```json
50+
{
51+
"value": "baz"
52+
}
53+
```
54+
55+
v2.1.0+:
56+
57+
```json
58+
{
59+
"value": "bar"
60+
}
61+
```
62+
63+
See [#2378](https://github.com/ruby-grape/grape/pull/2378) for details.
64+
1265
#### Grape::Router::Route.route_xxx methods have been removed
1366

1467
- `route_method` is accessible through `request_method`

lib/grape/extensions/hash.rb

+5-1
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@ module ParamBuilder
1212

1313
def build_params
1414
rack_params.deep_dup.tap do |params|
15-
params.deep_merge!(grape_routing_args) if env.key?(Grape::Env::GRAPE_ROUTING_ARGS)
1615
params.deep_symbolize_keys!
16+
17+
if env.key?(Grape::Env::GRAPE_ROUTING_ARGS)
18+
grape_routing_args.deep_symbolize_keys!
19+
params.deep_merge!(grape_routing_args)
20+
end
1721
end
1822
end
1923
end

spec/grape/extensions/param_builders/hash_spec.rb

+29
Original file line numberDiff line numberDiff line change
@@ -79,5 +79,34 @@ def app
7979
expect(last_response.status).to eq(200)
8080
expect(last_response.body).to eq('["bar", nil]')
8181
end
82+
83+
it 'does not overwrite route_param with a regular param if they have same name' do
84+
subject.namespace :route_param do
85+
route_param :foo do
86+
get { params.to_json }
87+
end
88+
end
89+
90+
get '/route_param/bar', foo: 'baz'
91+
expect(last_response.status).to eq(200)
92+
expect(last_response.body).to eq('{"foo":"bar"}')
93+
end
94+
95+
it 'does not overwrite route_param with a defined regular param if they have same name' do
96+
subject.namespace :route_param do
97+
params do
98+
requires :foo, type: String
99+
end
100+
route_param :foo do
101+
get do
102+
params[:foo]
103+
end
104+
end
105+
end
106+
107+
get '/route_param/bar', foo: 'baz'
108+
expect(last_response.status).to eq(200)
109+
expect(last_response.body).to eq('bar')
110+
end
82111
end
83112
end

spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb

+29
Original file line numberDiff line numberDiff line change
@@ -101,5 +101,34 @@ def app
101101
expect(last_response.body).to eq('["bar", "bar"]')
102102
end
103103
end
104+
105+
it 'does not overwrite route_param with a regular param if they have same name' do
106+
subject.namespace :route_param do
107+
route_param :foo do
108+
get { params.to_json }
109+
end
110+
end
111+
112+
get '/route_param/bar', foo: 'baz'
113+
expect(last_response.status).to eq(200)
114+
expect(last_response.body).to eq('{"foo":"bar"}')
115+
end
116+
117+
it 'does not overwrite route_param with a defined regular param if they have same name' do
118+
subject.namespace :route_param do
119+
params do
120+
requires :foo, type: String
121+
end
122+
route_param :foo do
123+
get do
124+
[params[:foo], params['foo']]
125+
end
126+
end
127+
end
128+
129+
get '/route_param/bar', foo: 'baz'
130+
expect(last_response.status).to eq(200)
131+
expect(last_response.body).to eq('["bar", "bar"]')
132+
end
104133
end
105134
end

spec/grape/extensions/param_builders/hashie/mash_spec.rb

+30
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,35 @@ def app
7575
expect(last_response.status).to eq(200)
7676
expect(last_response.body).to eq('["bar", "bar"]')
7777
end
78+
79+
it 'does not overwrite route_param with a regular param if they have same name' do
80+
subject.namespace :route_param do
81+
route_param :foo do
82+
get { params.to_json }
83+
end
84+
end
85+
86+
get '/route_param/bar', foo: 'baz'
87+
expect(last_response.status).to eq(200)
88+
expect(last_response.body).to eq('{"foo":"bar"}')
89+
end
90+
91+
it 'does not overwrite route_param with a defined regular param if they have same name' do
92+
subject.namespace :route_param do
93+
params do
94+
build_with Grape::Extensions::Hashie::Mash::ParamBuilder # rubocop:disable RSpec/DescribedClass
95+
requires :foo, type: String
96+
end
97+
route_param :foo do
98+
get do
99+
[params[:foo], params['foo']]
100+
end
101+
end
102+
end
103+
104+
get '/route_param/bar', foo: 'baz'
105+
expect(last_response.status).to eq(200)
106+
expect(last_response.body).to eq('["bar", "bar"]')
107+
end
78108
end
79109
end

0 commit comments

Comments
 (0)