diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b02b34310..0c46d4a150 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ #### Fixes * Your contribution here. +* [#2040](https://github.com/ruby-grape/grape/pull/2040): Fix a regression with Array of type nil - [@ericproulx](https://github.com/ericproulx). ### 1.3.2 (2020/04/12) diff --git a/README.md b/README.md index 0c0a7564bb..39618e7f5c 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ - [Include Parent Namespaces](#include-parent-namespaces) - [Include Missing](#include-missing) - [Parameter Validation and Coercion](#parameter-validation-and-coercion) + - [Structures Implicit Default Value](#structures-implicit-default-value) - [Supported Parameter Types](#supported-parameter-types) - [Integer/Fixnum and Coercions](#integerfixnum-and-coercions) - [Custom Types and Coercions](#custom-types-and-coercions) @@ -1070,6 +1071,26 @@ params do end ``` +### Structures Implicit Default Value + +There is an implicit default value when coercing for the following types with a nil value + +* Array = [] +* Array[ types ] = [] +* Set = Set +* Hash = {} + +```ruby +params do + requires :arry, type: Array +end +get '/array' do + params[:arry] +end + +get '/array', { arry: nil } + #=> [] +``` ### Supported Parameter Types The following are all valid types, supported out of the box by Grape: diff --git a/lib/grape/validations/validators/coerce.rb b/lib/grape/validations/validators/coerce.rb index 8934b2c495..be405c46af 100644 --- a/lib/grape/validations/validators/coerce.rb +++ b/lib/grape/validations/validators/coerce.rb @@ -76,9 +76,10 @@ def coerce_value(val) def coerce_nil(val) # define default values for structures, the dry-types lib which is used # for coercion doesn't accept nil as a value, so it would fail - return [] if type == Array + return [] if type == Array || type.is_a?(Array) return Set.new if type == Set return {} if type == Hash + val end diff --git a/spec/grape/validations/validators/coerce_spec.rb b/spec/grape/validations/validators/coerce_spec.rb index f0feff1769..e88a3ae3b7 100644 --- a/spec/grape/validations/validators/coerce_spec.rb +++ b/spec/grape/validations/validators/coerce_spec.rb @@ -424,6 +424,30 @@ def self.parsed?(value) expect(last_response.status).to eq(200) expect(last_response.body).to eq(integer_class_name) end + + context 'structures default value' do + [ + [Array, 'Array'], + [Set, 'Set'], + [Hash, 'ActiveSupport::HashWithIndifferentAccess'], + [Array[Integer], 'Array'] + ].each do |type, expected_class| + context 'structures default value' do + it 'respects the default value' do + subject.params do + requires :struct, type: type + end + subject.get '/default_value' do + params[:struct].class + end + + get '/default_value', struct: nil + expect(last_response.status).to eq(200) + expect(last_response.body).to eq(expected_class) + end + end + end + end end context 'using coerce_with' do @@ -752,19 +776,6 @@ def self.parsed?(value) expect(last_response.body).to eq('String') end - it 'respects nil values' do - subject.params do - optional :a, types: [File, String] - end - subject.get '/' do - params[:a].class.to_s - end - - get '/', a: nil - expect(last_response.status).to eq(200) - expect(last_response.body).to eq('NilClass') - end - it 'fails when no coercion is possible' do subject.params do requires :a, types: [Boolean, Integer]