-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Fix NoMethodError with none Hash params #1868
Conversation
ksss
commented
Mar 11, 2019
•
edited
Loading
edited
9f3fea8
to
72da4e6
Compare
I don't think the fix is correct. In the example case the type of items in |
|
||
it 'should pass none Hash params' do | ||
get '/test', foos: [''] | ||
expect(last_response.status).to eq(200) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this should be a 400. The first item in foos
does not match the expected input of my API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I followed this behavior.
params do
optional :foo
given :foo do
requires :bar
end
end
get('/test') { 'ok' }
client.get '/test', 'hello'
last_response.status #=> 200
last_response.body #=> "ok"
Is this also not intentional?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm. So we have this spec today? I feel that's wrong. Maybe @namusyaka or @dm1try have an opinion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dblock I do not see any contradiction in the examples above, in the latter case foo
is not provided, so it's not validated. in the original case foos
is provided, so it's validated.
according to the right behavior, if we assume that the implicit requirement for type: Array
with block is "array of objects"(Array[Object]
) then you are right, we should return a validation error(the string is not an "object", provided type is wrong).
in this PR, a type requirement is "array of something"(Array[Any]
) and this feels wrong, as for me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dm1try Just to confirm, you're saying this PR is good to go as is? Merge if yes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dblock I think it's fine, at least it's better than NoMethodError
.
though, in the future this spec should pass:
context 'group values' do
before do
subject.params do
requires :value, type: Hash do
end
end
subject.get('/hash') { }
subject.params do
requires :value, type: Array do
end
end
subject.get('/array_of_hashes') { }
end
it 'should be consistent' do
get '/hash', value: ""
expect(last_response.status).to eq(400)
expect(last_response.body).to eq("value is invalid")
get '/array_of_hashes', value: [""]
expect(last_response.status).to eq(400)
expect(last_response.body).to eq("value is invalid")
end
end
I've tested the idea to set implicit Array[Hash]
type here
if(block && (validations[:type].nil? || validations[:type] == Array))
validations[:type] = Array[Hash]
end
and while it works the case above, it fails for the cases where we rely on Virtus coerce logic for the hash
irb -Ilib -rgrape
irb(main):001:0> Virtus::Attribute.build(Array[Hash]).coerce({just: "hash"})
=> [{:just=>nil, "hash"=>nil}]
irb(main):002:0> Virtus::Attribute.build(Array).coerce({just: "hash"})
=> [[:just, "hash"]]
so this needs more investigation