I want to make HTTP requests from the browser to the server configured with XHR's withCredentials: true.
I found this documentation of java script.
Is there any similar thing in ruby on rails?
Is this config.http_authenticatable_on_xhr = true anyhow related to my requirement?
Thanks.
I fixed this by adding the below lines in a JS file and placing the file in the path app/assets/javascripts/ and including it in the app/assets/javascripts/application.js as //= require dummy_request
dummy_request.js contains:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com/', true);
xhr.withCredentials = true;
xhr.send(null);
Using the above technique you can send the request for the first time page being opened. If you want to make request for every particular interval, you can use something like below:
setInterval(function(){ var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com/', true);
xhr.withCredentials = true;
xhr.send(null); }, 3000);
Using the above code, you can send the request at an interval of every 3sec.
Thanks.
Related
I have a rails app in which I have used ajax calls with some url. I want to append project name to the ajax urls. One way is to edit all urls. Is there any other simpler way to do the same?
To prepend a word (let it be project_name) to all ajax calls in application write the following code in a js file:
$.ajaxSetup({
beforeSend: function(data, settings) {
var url = "/project_name"+ settings.url;
settings.url = url;
}
});
My google-map is only loading asynchronously after a page reload or an HTTP redirect. For the first onload, it won't appear-- none of the javascript is called.
In Rails development mode, it works without any problem. Likewise, the map loads asynchronously in production mode if I serve assets locally. But when I configure Amazon Web Services' Cloudfront CDN, it fails on the first page load.
Here's the javascript from the view that calls the map:
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.10.1.min.js"></script>
<script type="text/javascript">
function initialize() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
streetViewControl: false,
overviewMapControl: false,
mapTypeControl: false,
zoomControlOptions: {
style: google.maps.ZoomControlStyle.DEFAULT,
},
center: new google.maps.LatLng(39.82, -98.58),
});
// Info Window Content
var infoWindowContent = <%= raw #content %>;
var locations = <%= raw #location %>;
// Display multiple markers on a map
var infowindow = new google.maps.InfoWindow(), marker, i;
var marker, i;
var markers = new Array();
for (i = 0; i < locations.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][1], locations[i][2]),
map: map
});
markers.push(marker);
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent(infoWindowContent[i][0]);
infowindow.open(map, marker);
}
})(marker, i));
}
}
function loadScript() {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://maps.googleapis.com/maps/api/js?v=3.exp&' +
'callback=initialize';
document.body.appendChild(script);
}
window.onload =loadScript;
</script>
Any idea what may be going wrong with the code on AWS Cloudfront?
Wow. Finally solved this.
A few things went wrong.
First, AWS S3 and Cloudfront do not allow CORS, or Cross Origin Resource Sharing, by default. This means that you cannot call an AJAX resource served by either-- it won't work. That said, you can configure both to allow CORS. To do so, you need to edit your S3 bucket permissions and add a CORS Configuration (AWS offers good examples on help pages). Next, you need to whitelist the 'Origin' header on your Cloudfront distribution. This will allow cloudfront to forward the Origin header from the request to the response, and allow CORS. (I didn't fully get this to work. Check AWS help resources on CORS for more information)
Second, I noticed that even though my AJAX script was served locally and not by Cloudfront, a different javascript file was: my Turbolinks js file. It turns out the Turbolinks gem that the Rails Asset Pipeline requires creates a js file ended up being uploaded to my distribution (it's required by default in the application.js file). If you read the Turbolinks documentation, you'll see that Turbolinks ensures only reloads the html body and title of the head. Here's this from the README:
"Instead of letting the browser recompile the JavaScript and CSS between each page
change, it keeps the current page instance alive and replaces only the body and
the title in the head"
As it turns out, the Turbolinks interfered with the local AJAX and prevented the Google Map from loading asynchronously. Since the AWS CORS configuration evaded me, I simply added the option to turn turbolinks off for the link leading to the Google Map page:
data: { no_turbolink: true }
to make the full link:
<%=link_to "/map", data: { no_turbolink: true } %>
With no turbolinks, the page was never called using the Cloudfront Turbolinks.js file, and thus the local AJax could load the Google Map.
I hope this helps ye weary travelers!
I am trying to use Backbone.js models to save to my Yii web application but I am getting a "The CSRF token could not be verified" response even when the model is a serialized form and I use Backbone.sync to set a header.
The model (the form has the CSRF token in it and sends it as a "YII_CSRF_TOKEN" attribute):
var v = new ModelName ($('.formclass').serializeJSON());
JSON serializer:
//form.serializeJSON
(function( $ ){
$.fn.serializeJSON=function() {
var json = {};
jQuery.map($(this).serializeArray(), function(n, i){
json[n['name']] = n['value'];
});
return json;
};
})( jQuery );
The backbone.sync:
Backbone.old_sync = Backbone.sync;
Backbone.sync = function(method, model, options) {
var new_options = _.extend({
beforeSend: function(xhr) {
console.log('backbone sync');
var token = model.get('X_CSRF_TOKEN');
console.log('token ='+token)
if (token) xhr.setRequestHeader('YII_CSRF_TOKEN', token);
}
}, options)
Backbone.old_sync(method, model, new_options);
};
I have also tried setting the header as 'X_CSRF_TOKEN', to no avail.
YII_CSRF_TOKEN is not a header, it is just a form value.
According to this line our request have to contain
a CSRF cookie, it is already set by first, non-XHR page load
the form data value named YII_CSRF_TOKEN
If you send your data with save() you must send cookies and session id in parameters. See here a cached version of this blog post (cuz its offline now): http://webcache.googleusercontent.com/search?q=cache:tML1kmL08ikJ:blog.opperator.com/post/15671431847/backbone-js-sessions-and-authentication+&cd=1&hl=en&ct=clnk
If you're working on localhost, you might need to setup a Virtual Host to be able to perform cookie authentication as stated in this thread:this thread
IE and Chrome does not accept cookies from localhost so that could be the reason
I'm trying to build a mobile application with PhoneGap, jQuery Mobile and Backbone.js on the client-side - with a Rails 3 JSON API running server-side.
I know how to fetch the token from the server after being authenticated, but I don't know how to append the "token_auth" key/value to all the AJAX-requests Backbone.js will make to my server.
Here's my flow at the moment:
User types in some form fields and hits "Log in"
Backbone creates a new Player object with the email and password info.
I run a Player.authenticate that sets the token to AUTHENTICATION_TOKEN
All requests after this should append "auth_token=" + AUTHENTICATION_TOKEN
I've looked at http://documentcloud.github.com/backbone/#Sync for maybe overriding the AJAX calls - but that seems quite extreme for this simple task.
Does anyone have any experience with running Devise token_authentication and Backbone.js?
The key is to introduce it in the Backbone.sync method.
Take a look at this implementation: https://github.com/codebrew/backbone-rails/blob/master/vendor/assets/javascripts/backbone_rails_sync.js
You can add it yourself this way:
Backbone.old_sync = Backbone.sync
Backbone.sync = function(method, model, options) {
var new_options = _.extend({
beforeSend: function(xhr) {
var token = $('meta[name="csrf-token"]').attr('content');
if (token) xhr.setRequestHeader('X-CSRF-Token', token);
}
}, options)
return Backbone.old_sync(method, model, new_options);
};
Check out this fiddle: http://jsfiddle.net/dira/ZcY3D/14/
Why don't append it to all of your jquery ajax requests. It will add the auth_token to all of your ajax calls over jQuery. That might be useful when working directly with jQuery ajax (or libs that do so). But this might be a security issue as well (when you have ajax calls to other sites...).
// this is untested
$.ajaxSetup({ beforeSend : function(xhr, settings){
// just because the auth_token is a private information
if(!settings.crossDomain) {
// parse data object
var dataobj = JSON.parse(xhr.data);
// add authentication token to the data object
dataobj.auth_token = AUTHENTICATION_TOKEN;
// save the dataobject into the jqXHR object
xhr.data = JSON.stringify(dataobj);
}
}});
Another approach may be to write that token into the header and process it on the server side:
// thats not beautiful
$.ajaxSetup({ headers : { "auth_token" : AUTHENTICATION_TOKEN } });
Create a function like this that will send it any time an ajax request is sent to the server
$(function(){
$(document).ajaxSend(function(e, xhr, options) {
var token = $("meta[name='csrf-token']").attr("content");
xhr.setRequestHeader("X-CSRF-Token", token);
});
})
The Url for my development environment is:
http://localhost/mysite/blah...
I am using jQuery & getJSON to perform some ajax actions on my site, which work fine all the time I specify the url as:
/mysite/controller/action
..but this is not ideal as I don't want to hardcode my development url into my seperate jQuery include files.
When the site goes live, it'll be fine to have controller/action or /controller/action as the url as that will resolve ok, but for the development site, it's no go.
I've tried:
controller/action
..but this returns a 404, which suprised me as I thought the lack of / at the front of the url would prevent from looking at the website root.
There must be a neat solution to this?
I would do this by inserting a global constant in my HTML header:
<script type="text/javascript">
var BASE_URL = '/mysite/';
</script>
That would be inserted from your server so it can be dynamically changed.
Later in your script, you'll be able to make AJAX requests with (jQuery style here):
$.ajax( BASE_URL + '/controller/action', ...);
If you're in
/mysite/controller/action
then the correct relative path to
/mysite/some_other_controller/some_other_action
is
../../some_other_controller/some_other/action
You can use this code to get the current path of the .js script and use it for calculate your relative path.
var url;
$("script").each(function () {
if ($(this).attr("src").indexOf("[YOUR_SCRIPT_NAME.JS]") > 0) {
url = $(this).attr("src");
url = url.substr(0, url.lastIndexOf("/"));
return false;
}
});
var final_url = url + "/your_target_script.js"
Replace YOUR_SCRIPT_NAME with the unique name of your script.