Skip to content

Commit e0f412c

Browse files
author
Gwénaël Rault
authored
coerce_with should be called for params with nil value (#2164)
1 parent 8996fb1 commit e0f412c

File tree

5 files changed

+105
-2
lines changed

5 files changed

+105
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
* [#2161](https://github.com/ruby-grape/grape/pull/2157): Handle EOFError from Rack when given an empty multipart body - [@bschmeck](https://github.com/bschmeck).
1212
* [#2162](https://github.com/ruby-grape/grape/pull/2162): Corrected a hash modification while iterating issue - [@Jack12816](https://github.com/Jack12816).
13+
* [#2164](https://github.com/ruby-grape/grape/pull/2164): Fix: `coerce_with` is now called for params with `nil` value - [@braktar](https://github.com/braktar).
1314

1415
### 1.5.2 (2021/02/06)
1516

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,6 +1228,7 @@ params do
12281228
end
12291229
end
12301230
```
1231+
Note that, a `nil` value will call the custom coercion method, while a missing parameter will not.
12311232

12321233
Example of use of `coerce_with` with a lambda (a class with a `parse` method could also have been used)
12331234
It will parse a string and return an Array of Integers, matching the `Array[Integer]` `type`.

UPGRADING.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,33 @@
11
Upgrading Grape
22
===============
33

4+
5+
### Upgrading to >= 1.5.3
6+
7+
### Nil value and coercion
8+
9+
Prior to 1.2.5 version passing a `nil` value for a parameter with a custom coercer would invoke the coercer, and not passing a parameter would not invoke it.
10+
This behavior was not tested or documented. Version 1.3.0 quietly changed this behavior, in such that `nil` values skipped the coercion. Version 1.5.3 fixes and documents this as follows:
11+
12+
```ruby
13+
class Api < Grape::API
14+
params do
15+
optional :value, type: Integer, coerce_with: ->(val) { val || 0 }
16+
end
17+
18+
get 'example' do
19+
params[:my_param]
20+
end
21+
get '/example', params: { value: nil }
22+
# 1.5.2 = nil
23+
# 1.5.3 = 0
24+
get '/example', params: {}
25+
# 1.5.2 = nil
26+
# 1.5.3 = nil
27+
end
28+
```
29+
See [#2164](https://github.com/ruby-grape/grape/pull/2164) for more information.
30+
431
### Upgrading to >= 1.5.1
532

633
#### Dependent params

lib/grape/validations/types/custom_type_coercer.rb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,6 @@ def initialize(type, method = nil)
5252
# this should always be a string.
5353
# @return [Object] the coerced result
5454
def call(val)
55-
return if val.nil?
56-
5755
coerced_val = @method.call(val)
5856

5957
return coerced_val if coerced_val.is_a?(InvalidValue)

spec/grape/validations/validators/coerce_spec.rb

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,44 @@ def self.parse(_val)
706706
expect(JSON.parse(last_response.body)).to eq([1, 1, 1, 1])
707707
end
708708

709+
context 'Array type and coerce_with should' do
710+
before do
711+
subject.params do
712+
optional :arr, type: Array, coerce_with: (lambda do |val|
713+
if val.nil?
714+
[]
715+
else
716+
val
717+
end
718+
end)
719+
end
720+
subject.get '/' do
721+
params[:arr].class.to_s
722+
end
723+
end
724+
725+
it 'coerce nil value to array' do
726+
get '/', arr: nil
727+
728+
expect(last_response.status).to eq(200)
729+
expect(last_response.body).to eq('Array')
730+
end
731+
732+
it 'not coerce missing field' do
733+
get '/'
734+
735+
expect(last_response.status).to eq(200)
736+
expect(last_response.body).to eq('NilClass')
737+
end
738+
739+
it 'coerce array as array' do
740+
get '/', arr: []
741+
742+
expect(last_response.status).to eq(200)
743+
expect(last_response.body).to eq('Array')
744+
end
745+
end
746+
709747
it 'uses parse where available' do
710748
subject.params do
711749
requires :ints, type: Array, coerce_with: JSON do
@@ -754,6 +792,44 @@ def self.parse(_val)
754792
expect(last_response.body).to eq('3')
755793
end
756794

795+
context 'Integer type and coerce_with should' do
796+
before do
797+
subject.params do
798+
optional :int, type: Integer, coerce_with: (lambda do |val|
799+
if val.nil?
800+
0
801+
else
802+
val.to_i
803+
end
804+
end)
805+
end
806+
subject.get '/' do
807+
params[:int].class.to_s
808+
end
809+
end
810+
811+
it 'coerce nil value to integer' do
812+
get '/', int: nil
813+
814+
expect(last_response.status).to eq(200)
815+
expect(last_response.body).to eq('Integer')
816+
end
817+
818+
it 'not coerce missing field' do
819+
get '/'
820+
821+
expect(last_response.status).to eq(200)
822+
expect(last_response.body).to eq('NilClass')
823+
end
824+
825+
it 'coerce integer as integer' do
826+
get '/', int: 1
827+
828+
expect(last_response.status).to eq(200)
829+
expect(last_response.body).to eq('Integer')
830+
end
831+
end
832+
757833
context 'Integer type and coerce_with potentially returning nil' do
758834
before do
759835
subject.params do

0 commit comments

Comments
 (0)