Skip to content

Commit 633d7cf

Browse files
committed
Avoid coercing parameter with multiple types to an empty Array
If an optional parameter has multiple types (e.g. [File, String]) and a nil parameter is passed, Grape would previously coerce the value to an empty Array. This can break certain APIs that treat nil values differently from an empty Array. To fix this, we refactor the nil handling into a `coerce_nil` method and remove the special case check for handling an Array of types. Closes ruby-grape#2018
1 parent 8deebb5 commit 633d7cf

File tree

3 files changed

+41
-10
lines changed

3 files changed

+41
-10
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#### Fixes
1010

1111
* Your contribution here.
12+
* [#2019](https://github.com/ruby-grape/grape/pull/2018): Avoid coercing parameter with multiple types to an empty Array - [@stanhu](https://github.com/stanhu).
1213

1314
### 1.3.1 (2020/03/11)
1415

lib/grape/validations/validators/coerce.rb

+10-10
Original file line numberDiff line numberDiff line change
@@ -65,21 +65,21 @@ def valid_type?(val)
6565
end
6666

6767
def coerce_value(val)
68-
# define default values for structures, the dry-types lib which is used
69-
# for coercion doesn't accept nil as a value, so it would fail
70-
if val.nil?
71-
return [] if type == Array || type.is_a?(Array)
72-
return Set.new if type == Set
73-
return {} if type == Hash
74-
end
75-
76-
converter.call(val)
77-
68+
val.nil? ? coerce_nil(val) : converter.call(val)
7869
# Some custom types might fail, so it should be treated as an invalid value
7970
rescue StandardError
8071
Types::InvalidValue.new
8172
end
8273

74+
def coerce_nil(val)
75+
# define default values for structures, the dry-types lib which is used
76+
# for coercion doesn't accept nil as a value, so it would fail
77+
return [] if type == Array
78+
return Set.new if type == Set
79+
return {} if type == Hash
80+
val
81+
end
82+
8383
# Type to which the parameter will be coerced.
8484
#
8585
# @return [Class]

spec/grape/validations/validators/coerce_spec.rb

+30
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,23 @@ def self.parsed?(value)
180180
expect(last_response.body).to eq(integer_class_name)
181181
end
182182

183+
it 'String' do
184+
subject.params do
185+
requires :string, coerce: String
186+
end
187+
subject.get '/string' do
188+
params[:string].class
189+
end
190+
191+
get '/string', string: 45
192+
expect(last_response.status).to eq(200)
193+
expect(last_response.body).to eq('String')
194+
195+
get '/string', string: nil
196+
expect(last_response.status).to eq(200)
197+
expect(last_response.body).to eq('NilClass')
198+
end
199+
183200
it 'is a custom type' do
184201
subject.params do
185202
requires :uri, coerce: SecureURIOnly
@@ -647,6 +664,19 @@ def self.parsed?(value)
647664
expect(last_response.body).to eq('String')
648665
end
649666

667+
it 'respects nil values' do
668+
subject.params do
669+
optional :a, types: [File, String]
670+
end
671+
subject.get '/' do
672+
params[:a].class.to_s
673+
end
674+
675+
get '/', a: nil
676+
expect(last_response.status).to eq(200)
677+
expect(last_response.body).to eq('NilClass')
678+
end
679+
650680
it 'fails when no coercion is possible' do
651681
subject.params do
652682
requires :a, types: [Boolean, Integer]

0 commit comments

Comments
 (0)