How do you send JSON data in a rails-ujs Rails.ajax POST call (not using jQuery)?
Asked Answered
F

7

24

I have a React client app that needs to talk to a Rails API. I want to use the rails-ujs method Rails.ajax. For example:

Rails.ajax({
  type: "POST", 
  url: "/things",
  data: mydata,
  success: function(response) {...},
  error: function(response) {...}
})

It looks like I can't set data to a JSON object like this:

mydata = {
 thing: {
  field1: value1,
  field2: value2,
}}

I need to convert it to a application/x-www-form-urlencoded content type manually like this:

mydata = 'thing[field1]=value1&thing[field2]=value2'

This is ok for flat data but gets complicated quickly for nested data.

jQuery does the conversion automatically before making a request.

So I'm wondering if Rails UJS has some automatic way of doing it, but I couldn't find anything in the docs or code.

Factitive answered 22/8, 2017 at 14:35 Comment(2)
If you are trying to send form elements then Rails.serializeElement might help: rails-ujs/utils/form.coffeeDaphie
I got to your post learnetto.com/blog/rails-ajax and here too, and I was wondering if you found any more readable solution than formating them manyally?Stiles
G
17

When using Rails UJS, data must be formatted as string form parameters. Unfortunately, it's not possible to provide JSON, at least not currently with Rails 6.0.2 (not ideal).

Solution

Use URLSearchParams to convert JSON to URL paramaters:

myData = {
 thing: {
  field1: value1,
  field2: value2,
}}

Rails.ajax({
  type: "POST",
  url: "/things",
  data: new URLSearchParams(myData).toString()
})
Globate answered 15/12, 2019 at 0:55 Comment(2)
I get this error NoMethodError (undefined method permit' for "[object Object]":String):`Stiles
@Stiles You can't nest the data unfortunately with URLSearchParamsGabion
D
9

Here is my workaround to put/post with Content-Type: application/json.

It works by setting options.data in the beforeSend callback. This way the internal Rails.ajax.createXHR method does not set the Content-Type header first. https://github.com/rails/rails/blob/master/actionview/app/assets/javascripts/rails-ujs/utils/ajax.coffee#L53

    Rails.ajax({
      url: 'http://some-url.com',
      type: 'put',
      beforeSend(xhr, options) {
        xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8')
        // Workaround: add options.data late to avoid Content-Type header to already being set in stone
        // https://github.com/rails/rails/blob/master/actionview/app/assets/javascripts/rails-ujs/utils/ajax.coffee#L53
        options.data = JSON.stringify(data)
        return true
      },
    });
Dambrosio answered 20/11, 2019 at 19:27 Comment(2)
Had problems with trying to move away from jquery and javascript assets pipeline (move to webpacker) on a new rails 6 application. This was the only one that worked. My old jquery code just used a Get query and couldn't get that to work.Moved to a Post and this worked fine. It was even in a stimulus controllerFlowage
holy **, that's still valid for 2022. Couldn't find any other solution to send ajax with rails-ujsAurelio
N
7

I used ajax call several times and I used to send json data like this.

var fd = new FormData();
fd.append("jsondata", JSON.stringify(mydata));

$.ajax({
  url: ...
  type :"post",
  data: fd
  success:function(){
  }
})

Parsing Json data in ruby controller is easy. you can just use JSON.parse(params["jsondata"])
Hope this works for your case.

Newcomb answered 22/8, 2017 at 14:53 Comment(1)
That's not quite what I'm looking for. But thanks for your answer.Factitive
T
1

I reviewed the library code and It doesn't support that because in order to send an object you have to stringify the object, and after doing that I discovered that the library checks if the data is the type of string It changes the content type of the request to application/x-www-form-urlencoded . This link shows that condition in the library. And for that, your option to overcome this issue is to write a method that transforms the object to input form way or use JQuery Ajax or another library.

Thymic answered 23/8, 2017 at 8:46 Comment(1)
Yes, you're right, Ahmed. That's the bit of code I looked at too. I just wondered if there was another place where it pre-processes the data in case I had missed it. Thanks for your answer.Factitive
F
0

Not sure if I'm misunderstanding the issue, but can't you just convert your object using JSON.stringify?

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify

Certainly I can see in the rails-ujs module it's using JSON.parse to parse the Json response

Faintheart answered 25/8, 2017 at 6:11 Comment(2)
You're right, I can convert it myself. My question was if there's an inbuilt way in rails-ujs (like in jQuery, see processData). Also, I'm talking about JSON in the request data, not response.Factitive
I don't think it does, but not sure why that's a massive deal? It's pretty low overhead to JSON.stringify. Or am I not understanding what your trying to do?Faintheart
L
0

I noticed no actual solution for the stated problem, just workarounds.

Here is a link to a gist (JS class) that will handle the required serialization:

https://gist.github.com/dansimpson/231546

Lustre answered 25/4, 2022 at 16:2 Comment(0)
B
-2

you can set the content type in your ajax call and sending the data in json format

var data={
      user:{
        first_name: firstname,
        last_name: lastname,
        username: username
      }}

send the ajax call by placing content type as json in http header request

$.ajax({
   type: "POST",
   url: "http://someurl/post",
   data:data,
   contentType: "application/json",
   success: function(data) {
       -------
  }
});​
Bravura answered 21/11, 2019 at 4:33 Comment(1)
The OP mentions not jQuery, only RailsUJS library.Stiles

© 2022 - 2024 — McMap. All rights reserved.