diff --git a/CHANGELOG.md b/CHANGELOG.md index b9ba9c5677..a0dac4f50a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ Next Release ============ -* Your contribution here. +* [#864](https://github.com/intridea/grape/pull/864): Attributes with nil values should not be considered "missing"Your contribution here. - [@ppadron](https://github.com/ppadron). 0.10.0 (12/19/2014) =================== diff --git a/README.md b/README.md index 072b9d3cda..0d6c098984 100644 --- a/README.md +++ b/README.md @@ -638,6 +638,29 @@ curl -X POST -H "Content-Type: application/json" localhost:9292/users/signup -d } ```` +Note that an attribute with a `nil` value is not considered *missing* and will also be returned +when `include_missing` is set to `false`: + +**Request** + +````bash +curl -X POST -H "Content-Type: application/json" localhost:9292/users/signup -d '{"user": {"first_name":"first name", "last_name": null, "address": { "city": "SF"}}}' +```` + +**Response with include_missing:false** + +````json +{ + "declared_params": { + "user": { + "first_name": "first name", + "last_name": null, + "address": { "city": "SF"} + } + } +} +```` + ## Parameter Validation and Coercion You can define validations and coercion options for your parameters using a `params` block. diff --git a/UPGRADING.md b/UPGRADING.md index 640254da43..ffba9dfe57 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -1,6 +1,12 @@ Upgrading Grape =============== +### Upgrading to Next Release + +#### Changes to `include_missing` + +Attributes with `nil` values or with valus that evaluate to `false` are no longer considered *missing* and will be returned when `include_missing` is `false`. + ### Upgrading to >= 0.10.0 #### Changes to content-types diff --git a/lib/grape/dsl/inside_route.rb b/lib/grape/dsl/inside_route.rb index 1efc339e81..7920041fbb 100644 --- a/lib/grape/dsl/inside_route.rb +++ b/lib/grape/dsl/inside_route.rb @@ -38,7 +38,7 @@ def declared(params, options = {}, declared_params = nil) key.each_pair do |parent, children| output_key = options[:stringify] ? parent.to_s : parent.to_sym - next unless options[:include_missing] || children || params[parent] + next unless options[:include_missing] || children || params.key?(parent) if params.key?(parent) || options[:include_missing] hash[output_key] = if children diff --git a/spec/grape/endpoint_spec.rb b/spec/grape/endpoint_spec.rb index 2a15de1b5b..c31d39a161 100644 --- a/spec/grape/endpoint_spec.rb +++ b/spec/grape/endpoint_spec.rb @@ -328,6 +328,38 @@ def app expect(last_response.status).to eq(200) end + it 'should not consider as a missing attribute a value that evaluates to false' do + subject.params do + requires :first + optional :boolean + end + + subject.post '/declared' do + error!('expected false', 400) if declared(params, include_missing: false)[:boolean] != false + '' + end + + post '/declared', MultiJson.dump(first: 'one', boolean: false), 'CONTENT_TYPE' => 'application/json' + expect(last_response.status).to eq(201) + end + + it 'should not consider `nil` as a missing attribute' do + subject.params do + requires :first + optional :second + end + + subject.post '/declared' do + unless declared(params, include_missing: false)[:second].nil? + error!('expected nil', 400) + end + '' + end + + post '/declared', MultiJson.dump(first: 'one', second: nil), 'CONTENT_TYPE' => 'application/json' + expect(last_response.status).to eq(201) + end + it 'does not include missing attributes when there are nested hashes' do subject.get '/dummy' do end @@ -356,9 +388,9 @@ def app expect(last_response.status).to eq(200) expect(inner_params[:first]).to eq 'present' - expect(inner_params[:nested].keys).to eq [:fourth, :nested_nested] + expect(inner_params[:nested].keys).to eq [:fourth, :fifth, :nested_nested] expect(inner_params[:nested][:fourth]).to eq '' - expect(inner_params[:nested][:nested_nested].keys).to eq [:sixth] + expect(inner_params[:nested][:nested_nested].keys).to eq [:sixth, :seven] expect(inner_params[:nested][:nested_nested][:sixth]).to eq 'sixth' end end