Rails: Pass Params Through Ajax - ruby-on-rails

I need to pass params through javascript back to the server. At the moment, I pass them into javascript like so:
sendParams("<%= params[:q].to_json %>");
And then send them back like this:
function sendParams(q){
$.ajax({
url: '/mymodel/myaction',
type: 'post',
data: {'q':q},
contentType: 'json'
});
}
In my controller, I try to use them like I would any other params:
MyModel.where(params[:q])
But the params are coming back empty, even though firebug shows this in the POST tab:
q=%7B%26quot%3Bc%26quot%3B%3A%7B%26quot%3B0%26quot%3B%3A%7B%26quot%3Ba%26quot%3B%3A%7B%26quot%3B0%26quot%3B%3A%7B%26quot%3Bname%26quot%3B%3A%26quot%3Btitle%26quot%3B%7D%7D%2C%26quot%3Bp%26quot%3B%3A%26quot%3Bcont%26quot%3B%2C%26quot%3Bv%26quot%3B%3A%7B%26quot%3B0%26quot%3B%3A%7B%26quot%3Bvalue%26quot%3B%3A%26quot%3B2%26quot%3B%7D%7D%7D%7D%2C%26quot%3Bs%26quot%3B%3A%7B%26quot%3B0%26quot%3B%3A%7B%26quot%3Bname%26quot%3B%3A%26quot%3Bvotes_popularity%26quot%3B%2C%26quot%3Bdir%26quot%3B%3A%26quot%3Bdesc%26quot%3B%7D%7D%7D
Any idea why this information isn't getting processed by the where clause? What can I do to make the params Rails readable again?
UPDATE:
Started POST "/publications/search?scroll=active&page=6" for 127.0.0.1 at 2013-0
2-12 22:55:24 -0600
Processing by PublicationsController#index as */*
Parameters: {"scroll"=>"active", "page"=>"6"}
UPDATE 2:
The problem is apparently stemming from contentType. When I remove it, then q is sent as a Rails parameter. Unfortunately, q is still in JSON, resulting in the error:
undefined method `with_indifferent_access' for #<String:0x686d0a8>
How can I convert JSON to a params hash?

Your data parameter is wrong.
You have
data: {'q':q},
It should be
data: {q: 'q'},

There were a couple of issues that needed to be resolved for this to work. First, q wasn't being sent as a parameter to Rails, even though it was posting. The reason was because it was being treated as JSON data rather than as a parameter. I fixed this by removing the line:
contentType: 'json'
After that, the AJAX properly sent 'q', but Rails had trouble using it as it was in JSON. I had to parse it with ActiveSupport::JSON.decode, but this was throwing a 737: unexpected token error. I ran the code through (JSONlint)[http://jsonlint.com/], and it turns out that all the quotation marks had been escaped.
From there, there were two solutions. The obvious one was to use .html_safe like so:
sendParams("<%= params[:q].to_json.html_safe %>");
But this caused problems when the user inputed quotes. The safer alternative was to decode the escaped HTML entities after they were passed back to Rails like so:
ActiveSupport::JSON.decode(CGI.unescapeHTML(params[:q]))
And this did the trick.

Related

JSON parameters not available in request hash (Rails, omniauth-google-oauth2 gem)

Overview
I want to implement the Google OAuth2 server side (hybrid) with the Omniauth Google OAuth2 Gem (0.2.6). However, the code parameter I send to my app does not get added to the request.params hash. Thus, OmniAuth throws an error, as it can't find the code.
Details
After retrieving the auth code from Google I send it to the server (by AJAX):
// Send the code to the server
$.ajax({
type: 'POST',
url: '/auth/google_oauth2/callback',
contentType: 'application/json',
success: function(result) {
// Handle or verify the server response.
},
processData: false,
data: JSON.stringify(password_result)
});
This throws the error:
"error" : "invalid_request",
"error_description" : "Missing required parameter: code"
After going through the stack, I figured out the following:
As long as I have 'application/json' set as content Type, Rack parses the params correctly and the env object contains the parsed parameters:
"action_dispatch.request.request_parameters"=>{"code"=>"<sent_in_code>"}
However, the request.params hash remains empty. Since OmniAuth checks for request.params['code'], this is the source of the error.
request.POST is empty, which from looking at the source code of Rack is the underlying cause for the empty request.params hash.
When sending the code in standard format as data:"code="+authResult['code'], the parameter is available in the request.params hash. (I get a strange undefined route error then, but this is a different issue.)
Questions
Now, even though I can avoid the issue by not using JSON, I'm still very intereted in the answers to the following questions:
Why is the code parameter not available in request.POST/request.params, even though it gets parsed correctly?
Is there a way to fix this, so I can still send the auth code in JSON to my app?
I've spent two afternoons trying to get the answers myself, but haven't really gotten to a good conclusion so far.
omniauth-google-oauth2 tries to get the auth code from the Rack::Request.params hash. However, Rack apparently does not have JSON parsing built-in. Params calls POST which then calls form_data? which only looks for application/x-www-form-urlencoded or multipart/form-data. It then also tries parseable_data?, which does not parse JSON either. Seems like Rack does not support JSON out of the box, also look at this answer.
The "action_dispatch.request.request_parameters"=>{"code"=>"<sent_in_code>"} hash works because this is done by rails ActionDispatch::Request, which subclasses Rack::Request. However because The omniauth gem is included in your app as a Rack middleware, it does not know of the ActionDispatch request object.
The question remains why this example uses JSON.
Possible solutions:
money-Patch JSON Support into Rack - not recommended
just use application/x-www-form-urlencoded - recommended

How to access Rails params before all of the values are stringified?

I'd like to be able to inspect the params hash before all of the values are stringified by Rails. For example if I am using application/json Accept/Content-Type, and I receive:
{ "id":1, "post":"Hello" }
I want to be able to know that params[:id] was originally passed as a JSON integer, not a string.
I also want to be able to do this within a controller spec, which uses a limited set of middleware (or none at all?). Is this possible?
I believe this post has what you are looking for: How to access the raw unaltered http POST data in Rails?
request.raw_post
http://api.rubyonrails.org/classes/ActionDispatch/Request.html#method-i-raw_post

keys and values from an ajax POST are all escaped

I am trying to access some params from an ajax post in Rails. But my params are all escaped. I am not quite whether this is the best way to go about it. If I inspect the params[:event] vairable in Rails I end up receiving it looks something like this
{\"title\":\"None\",\"startdate\":\"2014-01-23\",\"enddate\":\"None\",\"description\":\" Description\"}
I am sure I can use this data if I really wanted to. But is this really the best way to receive data on my backend?
For reference, ajax
$.ajax ({
type: 'POST',
url: '/api/calendar',
dataType: 'json',
data: {'event': JSON.stringify(this)},
success: function(response) {
console.log('Success ', response);
}
});
Typical data
event:{
"title":"None",
"startdate":"2014-01-23",
"enddate":"None",
"description":"Description"
}
Two questions:
Is this the only way rails would accept data?
If this is the safest way to post data to my backend what would be the easiest way of accessing the data?
Any help would be appreciated, thank you
The JSON.stringify was the culprit. I was using a backbone model and switched to .toJSON instead.

How to indicate empty array in HTTP request query params?

This is the way Rails accepts arrays in query parameters:
PUT /resource.json?sport_ids[]=133&sport_ids[]=64&sport_ids[]=71 ...
I tried to google this question but didn't find any explicit docs on it:
How to tell Rails that we want sport_ids to become empty (pass empty array of sport_ids via query parameters) ?
HTTP requests can have only variables on the url itself. That's a limitation feature of HTTP, not Rails.
Take a look at How Does Rack Parse Query Params? With Parse_nested_query to figure out how rails collects the variables into an array, it won't run out of the box in case of an empty array.
You can avoiding sending the params["sport_ids"] and patch your controller with:
params["sport_ids"] ||= []
The best practice to use put/post requests, is passing such data in the request body (json/xml) like:
{
"sport_ids": []
}
Or with data as:
//...
{
"sport_ids": [133, 64, 71]
}
//...
For more info about HTTP request steps, check Running a HTTP request with rails.
While #mohameddiaa27's answer has good advice on how to achieve that by passing such data in the request body as JSON I found that I cannot rely on it within my application: I found that it is not easy to combine such passing of JSON into request body within multipart forms where I want to pass user record (with user[sport_ids] in it) and user's avatar image (user[avatar]) field.
So I continued to investigate how to achieve that using default "query parameters in a request body of POST/PUT request" approach and found the reason why I was not able to reset my sport_ids on server-side: it was the lack of permission for that specific sport_ids field. Now I have the following permits (pseudocode):
current_user.update!(user_params)
where user_params is
user_attributes_to_permit = [
...
:sport_ids, # this is what was needed for just `user[sport_ids]` to work.
{ :sport_ids => [] } # this is needed for sport_ids non-empty arrays to work
...
]
params.require(:user).permit(user_attributes_to_permit)
so now I am able to reset the sport_ids array of my user by passing just user[sport_ids] (without '=' and value! i.e. ...&user[sport_ids]&...) within my query parameters.

RoR: POST to a page using raw form data. How?

Is there a ruby method to POST form data encoded in "x-www-form-urlencoded" as specified here? http://www.w3.org/MarkUp/html-spec/html-spec_8.html
I am aware of Net::HTTP.post_form, but because I have several values to post which share the same name I can't use a hash, which is required by that method.
To clarify, I have a string of the form "value1=x&value1=y&value1=z&value2=a&value3=b" and I want to be able to POST it to another page. How can I do this?
I think internally the params object is a parsed version of the actual raw post body in the http request. All post data is posted the same way (as raw post data), but the params hash in ActionController has already parsed this into an easy-to-use hash. If you actually need the raw post data from a form, you can access it through the raw_post method of the request object itself.
The ActionController::Request.raw_post documentation here is for rails3, but has been available since at least 2.3.8 (the only 2.3.x version I checked). I think it most likely has been available longer than that.
In a controller, try self.request.raw_post to get the raw post data as a string.
Are you able to have a hash value which is an Array? I think that this is the way parameters with the same names are usually handled.

Resources