I’m trying to write a set of rspec tests for a JSON API written in Rails 3.2 with Backbone as the front end. The tests I’m writing are specifically for the Rails controllers.
Now, the application itself is working fine. When a client issues a PUT request with the body:
{
"id":1,
"name":"updated product set",
...
}
Everything is great. In the background Rails will take that body, then transform it into:
{
"id":1,
"name":"updated product set",
...
"model_name" => { ... }
}
where the hash “model_name” points to contains the attribute values it can automatically figure out from the input. All is well.
When I try the same exact request from the testing environment, all is not well. If I create a hash that is exactly the same PUT body hash as above, but in rspec:
@update_json = {
"id":1,
"name":"updated product set",
...
}
header "Accept","application/json"
header "Content-type","application/json"
put :update, @update_json
Things do not work out at all. In the controller, if I inspect the params variable I get:
{ "model_name" => {} }
If I omit the “Content-type” header line, I get instead @update_json, but without the Rails manipulation that creates the “model_name” mapping which I require in my controller.
The only way I’ve gotten a successful test to run is the following:
@update_json = {
:format => "json",
"id":1,
"model_name" => {
"id":1,
"name":"updated product set",
...
}
}
header "Accept","application/json"
put :update, @update_json
However, this is not a real-world test since it’s not testing the exact PUT body that would be sent by my backbone front-end.
Any ideas?
UPDATE:
From looking around it looks like you can’t actually do a real HTTP request from rspec; it’s just mocked up. For example, you can’t get the system to respond with a 404 since Rails throws an Exception that would normally be caught by Rails network stack and turned into a 404 but which isn’t with Rspec. So the problem looks deeper than what’s above…
I was having the same problem. No matter what I did, or which ways I specified the content type as ‘application/json’, it just wouldn’t work. If there was a suggestion on the internet for setting the content type to json, I tried it. I even tried them all together at the same time.
Ultimately, I traced it to ActionController::ParamsWrapper, where _wrapper_enabled? was always returning false (due to request.content_mime_type being nil). This solution works for me. I was looking for the ‘magical’ params key to get added as well and this does it.
The values are:
This is exactly what I wanted. Only title, order, and description are set as attr_accessible, hence the only attributes that appear in the magically created :widget hash.
I am also using active_model_serializers, so the as_json is running through that, in case anyone thinks it matters.
This is part of a public example app I’m building, so this code will be able to be seen in use, if anyone thinks it might be useful.