Rails session doesn't saved during ajax call - ruby-on-rails

I have this ajax call after completing specific action
$.ajax({
type: "POST",
url: $("#myform").prop('action'),
data: $("#myform").serialize(),
xhrFields: {withCredentials: true},
beforeSend: function(xhr) {
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').last().attr('content'));
}
});
this ajax call refering to create action, so I wanna save the params of the form in the session I've created before. so I put this in create action
def create
session[:my_session].deep_merge!(params[:user])
puts session[:my_session]
I print the session to make sure from the server that it contains the right params, and Yeah, it has been printed with the right values.
{"profile_id"=>"1000", "first_name"=>"john", "last_name"=>"vieira", "email"=> "john#sandsora.com"}
the problem here is after that call, the session doesn't save the data which I've stored!, which means that it stored the latest data before this assignment. I searched for that error and I got that it may be CSRF token error and I fixed it by adding beforeSend function, but I still have the same problem, so any suggestions please?

My first guess would be that the session cookie headers are not being set. Without this cookie rails has not way of setting the correct session and you data is "lost" after the request has completed. Your browser should send it automatically on your ajax requests though...
Can you verify that the session cookie is being sent with your ajax request?

Related

Rails authenticity token (CSRF) provided but being refused

I'm sending an AJAX request from my rails site to itself (to go from javascript to a controller). Rails refuses to allow the POST unless I supply an authenticity token, so I added one using
<%= csrf_meta_tags %>
and
var AUTH_TOKEN = "<%=j form_authenticity_token %>"
and everything was fine. However, a new customer recently installed the plugin that accesses my site and triggers the AJAX in the first place. But for this one customer--the authenticity token was denied, despite being supplied (I checked in the logs.)
I realize I'm not giving a lot of clues to go off of, but what could cause the authenticity token to be accepted in one situation and denied in another? More broadly, how is the authenticity_token generated anyways--a new one every single time the page is loaded?
Rails assigns a cryptographically random CSRF token to the the user session.
The server compares the value submitted for the authenticity_token parameter to the value associated with the user’s session.
One thing you especially need to be careful with is that if you are using fragment caching (which speeds up rendering by caching chunks of the view) you need to ensure that your <%= csrf_meta_tags %> are not cached since a stale csrf meta tag will lead to mismatch with the token stored in the session.
When posting with ajax, you need to forward the CSRF token with the X-CSRF-Token header.
var promise = $.ajax({
url: '/example',
type: 'POST',
beforeSend: function(xhr) {
xhr.setRequestHeader('X-CSRF-Token',
$('meta[name="csrf-token"]').attr('content'))
},
data: 'someData=' + someData
});

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.

Custom post using angular rails resource

Hi I'm using rails and angularjs with the angularrailsresource gem. I need to do a custom post request to a rails resource I have defined called 'Comment'. I tried using the $post method like this:
Comment.$post('some_method', {comment_id: comment.id, username: username, type: 'mention'}).then(function(result){
console.log(result);
});
and it makes a request but it always makes it under the root of the page I'm on. So I want to make a request to '/comments/', but it tries to make a request to '/patients/some_method' and if I do this:
Comment.$post('comments/do_stuff', {comment_id: comment.id, username: username, type: 'mention'}).then(function(result){
console.log(result);
});
it will try to post to 'patients/comments/some_method', or whatever else the root of the page I'm on is. Is there a way to tell it to post directly to the resource and not through the the url context that I am currently on? Thank you for your help.
You have to use the path with a / before it, otherwise it will trigger the action using the relative path. Try this:
Comment.$post('/comments/do_stuff' ....
Notice the / before comments.

ajaxSetup not working with Rails / jquery-ujs

I'm working on a project that makes heavy usage of XHR, and there is some data that needs to be appended to each ajax request in order for the server side to properly keep track of what is going on in the browser.
I have a generic class called xhr_response_handler than I use to handle the callbacks for all ajax requests that is added to all forms, links etc that is making ajax requests. (i.e. where ":remote => true" in rails)
$('.xhr_response_handler')
.on('ajax:success', function(event, data, status, xhr) { xhr_success(data); })
.on('ajax:failure', function(xhr, status, error) { xhr_fail(error); });
Then I try to append the default data sent with each request using:
$.ajaxSetup({
data: {
Foo: <%= #Bar %>
}
});
This works for some of the elements where the ajax settings are configured directly with jquery, but this does not work for some elements created using rails methods like link_to and form_for with :remote => true.
The odd thing is that if I also add
$('.xhr_response_handler').data( 'params', { Foo2: <%= #Bar2 %> } );
Then that works for adding data to the rails generated ajax requests using link_to. What makes it odd is that now all of a sudden the ajaxSettings also works, and in the ajax requests I get both Foo and Foo2 as parameters. But I get no parameters at all when using ajaxSettings by itself.
Furthermore, none of the data to be appended gets serialized into the form data sent in ajax requests generated from the rails form_for method.
Any help would be appreciated.
Rails 3.2.3
Ruby 1.9.3p194
jQuery 1.7.2
I think this behaviour appears because the data hash of $.ajaxSetup is overridden by the ajax calls you do later on. The data has to be merged manually.

How do you send a request with the "DELETE" HTTP verb?

I'd like to create a link in a view within a Rails application that does this...
DELETE /sessions
How would I do that.
Added complication:
The "session" resource has no model because it represents a user login session. CREATE means the user logs in, DESTROY means logs out.
That's why there's no ID param in the URI.
I'm trying to implement a "log out" link in the UI.
Correct, browsers don't actually support sending delete requests. The accepted convention of many web frameworks is to send a _method parameter set to 'DELETE', and use a POST request.
Here's an example in Rails:
<%= link_to 'log out', session_path, :method => :delete %>
You may want to have a look at Restful Authentication.
I don't know about Rails specifically, but I frequently build web pages which send DELETE (and PUT) requests, using Javascript. I just use XmlHttpRequest objects to send the request.
For example, if you use jQuery:
have a link that looks like this:
<a class="delete" href="/path/to/my/resource">delete</a>
And run this Javascript:
$(function(){
$('a.delete').click(function(){
$.ajax(
{
url: this.getAttribute('href'),
type: 'DELETE',
async: false,
complete: function(response, status) {
if (status == 'success')
alert('success!')
else
alert('Error: the service responded with: ' + response.status + '\n' + response.responseText)
}
}
)
return false
})
})
I wrote this example mostly from memory, but I'm pretty sure it'll work....
Correct me if I'm wrong, but I believe you can only send POST and GET requests with a browser (in HTML).
Rails' built in method for links will generate something like this:
Logout
If you don't want to use the Rails' built in method (i.e. don't want the rel="nofollow", which prevents search engine crawlers from following the link), you can also manually write the link and add the data-method attribute, like so:
Logout
Browsers can only send GET/POST requests, so this will send a normal GET request to your Rails server. Rails will interpret and route this as a DESTROY/DELETE request, and calls the appropriate action.

Resources