as a request spec both of these fails because they get converted into strings.
require 'spec_helper'
describe 'parameters' do
before { post 'orders.json', order: {boolean: true, integer: 123} }
it 'should have boolean value' do
request.params['order']['boolean'].should == true
end
it 'should have integer value' do
request.params['order']['integer'].should == 123
end
end
as a controller spec boolean passes, integer fails.
require 'spec_helper'
describe OrdersController do
before { post :create, order: {boolean: true, integer: 123} }
it 'should have boolean value' do
controller.params['order']['boolean'].should == true
end
it 'should have integer value' do
controller.params['order']['integer'].should == 123
end
end
This is with Rails 3.2.8 and RSpec 2.11.0
You'll want to post this to the https://github.com/rails/rails/issues as the conversions happen in ActionDispatch::Integration::Runner for request specs and ActionController::TestCase::Behavior for controller specs.
This is actually by design: URL parameters will come into your application as strings. e.g., http://example.com/?foo=bar&baz=1 will be parsed into params as { :foo => "bar", :baz => "1" }. There's no information the application can use to correctly type values as anything but strings.
The specifics of request vs. controller specs are a bit more complicated if I remember correctly. I believe request specs have always exhibited this behavior; controller specs changed with this Rails commit: https://github.com/rails/rails/commit/7fd726d62e8483c5bdb39c7f5b9d267e6b7fbaa6
tldr: it's more realistic that the parameters come in as strings because that's what will happen in real HTTP requests.
The problem I'm finding is if I pass in a boolean or integer through the actual application I'll get the boolean or integer value and not as a string.
In the actual application, is the data coming across as URL-encoded form data .. or something like JSON (which has support for certain types, including numbers and booleans)?
It's coming in as JSON and not form data.
@alindeman @vizjerai you're welcome to continue this convo here, but this is a Rails issue, not RSpec, so we can't fix it here. I'd recommend opening a similar issue in the Rails project.
@dchelimsky, agreed. I think RSpec and Rails are operating correctly: I am just trying to be a bit helpful, though maybe there are better venues for that?
@vizjerai, JSON data can be typed, so that's why you're seeing things correctly in production. The request and controller specs you showed are submitting parameters via URL parameters/form data ... so there's a mismatch between your tests and reality. Rails is trying to be helpful by stringifying/paramifying as would happen in reality if the parameters were form data.
This is one way to submit JSON in a Rails integration test (a.k.a RSpec request spec):
post 'orders.json', JSON.dump(order: {boolean: true, integer: 123}),
"CONTENT_TYPE" => "application/json"
@alindeman, thanks that works great for the request specs. But I'm at a loss on how to get the controller specs to work correctly...
@alindeman, Nevermind, it works. I forgot I rolled back the version of rails I had that was before the change you mentioned to rails above.
post :create, order: {boolean: true, integer: 123}, format: :json
If anyone's struggling with this, as of rails 4.2, you can get it to work with:
post :create, {order: {boolean: true, integer: 123}, :format => :json}
Shoutout to these folks
In Rails5, I seem to be having this problem again. Even with format: :json, all integers get turned into strings, which does _not_ match how Rails is actually delivering them to me in production (from a json-format post'd body).
Is there a regression in rails5?
@jrochkind try as: :json
Yep, that's what worked. Sorry I forgot to come back and update, I was knee deep in yak shaving.
Not sure where one would have figured that out from any documentation (and I honestly still don't really understand what's going on here), but hey now it's here for those who end up here by googling, thanks @bkudria!
In rails 4.2.9, Rspec 3.6, I had to do post :create, params.merge(format: :json) to make it work. This was very annoying!!
Most helpful comment
@jrochkind try
as: :json