How to send raw data to Rails functional test?

I want to send the source data (e.g. unparamaterized json) to one of my controllers for testing:

 class LegacyOrderUpdateControllerTest < ActionController::TestCase test "sending json" do post :index, '{"foo":"bar", "bool":true}' end end 

but it gives me NoMethodError: undefined method `symbolize_keys' for #<String:0x00000102cb6080>

What is the correct way to send raw data to ActionController :: TestCase?

Here is the controller code

 def index post_data = request.body.read req = JSON.parse(post_data) 
+49
json ruby-on-rails testing
Jan 20
source share
11 answers

Today I ran into the same problem and found a solution.

In your test_helper.rb, define the following method inside ActiveSupport :: TestCase:

  def raw_post(action, params, body) @request.env['RAW_POST_DATA'] = body response = post(action, params) @request.env.delete('RAW_POST_DATA') response end 

In your functional test, use it in the same way as the post method, but pass the original message body as the third argument.

 class LegacyOrderUpdateControllerTest < ActionController::TestCase test "sending json" do raw_post :index, {}, {:foo => "bar", :bool => true}.to_json end end 

I tested this on Rails 2.3.4 while reading the original message body using

 request.raw_post 

instead

 request.body.read 

If you look at the source code , you will see that raw_post just wraps request.body.read with the check for this RAW_POST_DATA in an env hash request.

+55
Jan 21 '10 at 3:19
source share

I actually solved the same problems by simply adding one line before simulating an rspec post request. What are you doing is filling out "RAW_POST_DATA". I tried removing the var attributes in the: create message, but if I do, it does not find the action.

Here is my solution.

 def do_create (attributes)
   request.env ['RAW_POST_DATA'] = attributes.to_json
   post: create, attributes
 end 

In the controller, the code needed to read JSON is something like this

   @property = Property.new (JSON.parse (request.body.read))
+15
Jan 12 2018-11-11T00:
source share

If you look at the stack trace in which the test is run, you can get more control when preparing the request: ActionDispatch :: Integration :: RequestHelpers.post => ActionDispatch :: Integration :: Session.process => Rack :: Test :: Session. env_for

You can pass the json string as: params and specify the content type "application / json". Otherwise, the content type will be set to "application / x-www-form-urlencoded" and your json will parse correctly.

So all you need is to specify "CONTENT_TYPE":

 post :index, '{"foo":"bar", "bool":true}', "CONTENT_TYPE" => 'application/json' 
+9
Oct 28 2018-11-11T00:
source share

If you use RSpec (> = 2.12.0) and write down the specification of the request, the module that is included is ActionDispatch::Integration::Runner . If you look at the source code, you will notice that the post method calls a process that takes the rack_env parameter.

All of this means that you can simply do the following in your specification:

 #spec/requests/articles_spec.rb post '/articles', {}, {'RAW_POST_DATA' => 'something'} 

And in the controller:

 #app/controllers/articles_controller.rb def create puts request.body.read end 
+4
Jan 28 '13 at 19:51
source share

Version for Rails 5:

 post :create, body: '{"foo": "bar", "bool": true}' 

See here - body string parameter is treated as the body of the raw request.

+2
Apr 25 '17 at 15:18
source share

For those using Rails5 + integration tests, the way (undocumented) for this is to pass a string in the params argument, therefore:

 post '/path', params: raw_body, headers: { 'Content-Type' => 'application/json' } 
+2
Jun 26 '17 at 1:30
source share

Using Rails 4, I tried to do this to test the raw xml processing that was sent to the controller. I was able to do this by simply providing a line in the message:

 raw_xml = File.read("my_raw.xml") post :message, raw_xml, format: :xml 

I believe that if the provided parameter is a string, it is simply passed along with the controller as a body.

+1
May 14 '15 at 17:45
source share

The post method expects a hash of name / value pairs, so you need to do something like this:

 post :index, :data => '{"foo":"bar", "bool":true}' 

Then, in your controller, get the data for analysis as follows:

 post_data = params[:data] 
0
Jan 20 '10 at 19:00
source share

Like Rails 4.1.5, this is the only thing that worked for me:

 class LegacyOrderUpdateControllerTest < ActionController::TestCase def setup @request.headers["Content-Type"] = 'application/json' end test "sending json" do post :index, '{"foo":"bar", "bool":true}'.to_json, { account_id: 5, order_id: 10 } end end 

for the url in / accounts / 5 / orders / 10 / items. This receives the passed URL parameters as well as the JSON body. Of course, if orders are not built in, you can leave a hash of params.

 class LegacyOrderUpdateControllerTest < ActionController::TestCase def setup @request.headers["Content-Type"] = 'application/json' end test "sending json" do post :index, '{"foo":"bar", "bool":true}'.to_json end end 
0
May 19 '15 at 19:16
source share

In rails 5.1, the following work is done for me when I execute a delete request, which requires data in the body:

 delete your_app_url, as: :json, env: { "RAW_POST_DATA" => {"a_key" => "a_value"}.to_json } 

NOTE: This only works when performing the integration test.

0
Oct 31 '17 at 20:26
source share
 post :index, {:foo=> 'bar', :bool => 'true'} 
-5
Jan 20 '10 at 18:44
source share



All Articles