Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optional values with multiple types get coerced to an empty Array #2018

Closed
stanhu opened this issue Mar 17, 2020 · 0 comments · Fixed by #2019
Closed

Optional values with multiple types get coerced to an empty Array #2018

stanhu opened this issue Mar 17, 2020 · 0 comments · Fixed by #2019

Comments

@stanhu
Copy link
Contributor

stanhu commented Mar 17, 2020

This breaks certain APIs that expect a parameter passed in with nil to remain nil. To reproduce the problem:

diff --git a/spec/grape/validations/validators/coerce_spec.rb b/spec/grape/validations/validators/coerce_spec.rb
index dbf57c9..cb2cca5 100644
--- a/spec/grape/validations/validators/coerce_spec.rb
+++ b/spec/grape/validations/validators/coerce_spec.rb
@@ -647,6 +647,19 @@ describe Grape::Validations::CoerceValidator do
         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]

This is the test failure:

  2) Grape::Validations::CoerceValidator coerce multiple types respects nil values
     Failure/Error: expect(last_response.body).to eq('NilClass')

       expected: "NilClass"
            got: "Array"

       (compared using ==)
     # ./spec/grape/validations/validators/coerce_spec.rb:660:in `block (4 levels) in <top (required)>'

It looks like this happens because of this code block:

# 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
if val.nil?
return [] if type == Array || type.is_a?(Array)

I'm not quite sure I understand why the type.is_a?(Array) check needs to be there. This allows tests to pass:

$ git diff
diff --git a/lib/grape/validations/validators/coerce.rb b/lib/grape/validations/validators/coerce.rb
index 561ec1b..b2b4cbf 100644
--- a/lib/grape/validations/validators/coerce.rb
+++ b/lib/grape/validations/validators/coerce.rb
@@ -68,9 +68,10 @@ module Grape
         # 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
         if val.nil?
-          return []      if type == Array || type.is_a?(Array)
+          return []      if type == Array
           return Set.new if type == Set
           return {}      if type == Hash
+          return val
         end

         converter.call(val)

Also, if we need to accept nil as a coerced value, there is https://github.com/dry-rb/dry-types/blob/bd75d556e70c2d3bef1f96140a8f33fb44c31f9d/docsite/source/optional-values.html.md.

stanhu added a commit to stanhu/grape that referenced this issue Mar 17, 2020
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.

Closes ruby-grape#2018
stanhu added a commit to stanhu/grape that referenced this issue Mar 17, 2020
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.

Closes ruby-grape#2018
stanhu added a commit to stanhu/grape that referenced this issue Mar 17, 2020
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.

Closes ruby-grape#2018
stanhu added a commit to stanhu/grape that referenced this issue Mar 17, 2020
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.

Closes ruby-grape#2018
stanhu added a commit to stanhu/grape that referenced this issue Mar 17, 2020
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.

Closes ruby-grape#2018
stanhu added a commit to stanhu/grape that referenced this issue Mar 17, 2020
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
stanhu added a commit to stanhu/grape that referenced this issue Mar 17, 2020
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
stanhu added a commit to stanhu/grape that referenced this issue Mar 17, 2020
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant