RAW_POST_DATA in rspec rails for Rails 5.2 and beyond

The last time I was trying to specify RAW_POST_DATA in rspec was probably Rails 3 or 4, but I ran into a situation trying to test an edge case for error handling where I wanted that same functionality. I quickly found this issue [Unable to POST raw request body], but didn’t immediately figure out what wasn’t being set correctly.

In this case the test setup I was using was setting multipart/form-data instead of application/xml on the content types:

{:HTTP_ACCEPT=>"application/xml", :HTTP_CONTENT_TYPE=>"multipart/form-data", :CONTENT_TYPE=>"multipart/form-data"}

Because of this, the Rails controller tests that rspec hooks into was trying to break following malformed xml down to parameters:

            <test>
              <data&nbsp;
              <![CDATA[THIS|IS|SENSITIVE|BUT|MALFORMED]]>
              </data>
            </test>
 Minitest::Assertion:
   Expected response to be a <400: bad_request>, but was a <422: Unprocessable Entity>
   Response body: <errors>
       <error>["<test>\n  <data", "nbsp;\n  <!"] are not permitted parameters</error>
   </errors>

I finally noticed that the mime-type might be involved. In this code, Content-Type was also an issue, so:

  • Removed HTTP_CONTENT_TYPE from the headers
  • Set CONTENT_TYPE header to 'application/xml' instead of 'multipart/form-data' to prevent automatic params parsing in this case.
  • Passed as: :xml into the test to get the 'mime-type' correct.

Ultimately, if your code hasn’t boxed you in, then the as: :xml and passing raw data as a parameter should work:

post things_path, params: raw_xml_data, headers: non_form_data_headers, as: :xml

## replacement for the following:
# @request.env['RAW_POST_DATA'] = raw_xml_data
# post things_path