Skip to content

Instantly share code, notes, and snippets.

@collectiveidea
Created August 21, 2009 19:59
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save collectiveidea/172391 to your computer and use it in GitHub Desktop.
Save collectiveidea/172391 to your computer and use it in GitHub Desktop.
How to get jQuery to work with Rail's Authenticity Token (protect_from_forgery)
<!DOCTYPE html>
<html>
<head>
<title>My Rails App</title>
<%- if protect_against_forgery? -%>
<meta name="authenticity-token" id="authenticity-token" content="<%= form_authenticity_token %>" />
<%- end -%>
<%= javascript_include_tag 'jquery', 'rails' %>
</head>
<body>
<h1>Using jQuery with Rails' Authenticity Token</h1>
<p>
By putting the authenticity token in the head, we can easily grab it from JS.
</p>
</body>
</html>
(function($) {
$.ajaxSettings.accepts.html = $.ajaxSettings.accepts.script;
$.authenticityToken = function() {
return $('#authenticity-token').attr('content');
};
$(document).ajaxSend(function(event, request, settings) {
if (settings.type == 'post') {
settings.data = (settings.data ? settings.data + "&" : "")
+ "authenticity_token=" + encodeURIComponent($.authenticityToken());
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
}
});
})(jQuery);
@codesoda
Copy link

A current and simpler way to do this...

$(function(){
  // always pass csrf tokens on ajax calls
  $.ajaxSetup({
    headers: { 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content') }
  });
});

@Metaphysiker
Copy link

This doesn't work for me.

  1. I added jqueryauthenticity.js to app/assetsjavascripts

  2. I added code to jqueryauthenticity.js

#  jqueryauthenticity.js
$(function(){
  // always pass csrf tokens on ajax calls
  $.ajaxSetup({
    headers: { 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content') }
  });
});
  1. I added //= require jqueryauthenticity to application.js
#application.js
//= require rails-ujs
//= require turbolinks
//= require clipboard
//= require clipboardtooltip
//= require jqueryauthenticity
//= require_tree .

Where did I go wrong?

(I'm using a CDN for jQuery, does this matter?)

@brendon
Copy link

brendon commented Jun 20, 2019

This works well:

$.ajaxPrefilter(function(options, originalOptions, xhr) {
  if (!options.crossDomain) {
    token = $('meta[name="csrf-token"]').attr('content');
    if (token) xhr.setRequestHeader('X-CSRF-Token', token);
  }
});

It's basically exactly what jquery-ujs does. No need to wrap it in a $(function(){});

@benlieb
Copy link

benlieb commented Apr 5, 2020

I had an awful time getting this to work, but ATM I'm on the "bleeding edge" and seeing the blood, using Rails 6, webpacker, React. The problem I was having was a combination of load order and the actual instance of jQuery being used inside of @rails/ujs (and also tried jquery-ujs). None of them worked for me.

I was trying to make $ available from inside my environment.js file... By the time the $ was made available inside my react components, it was no longer the same instance as what was used in the ujs files, so the config didn't "take".

My final "solution" that allowed my authenticity token to be sent properly from $.ajax in my react components was to import a "configured" $ manually like this:

utils/jquery.js:

import $ from 'jquery'

$(function(){
  // always pass csrf tokens on ajax calls
  $.ajaxSetup({
    headers: { 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content') }
  });
});

export default $

And inside React component:

import $ from '../utils/jquery'

I'm far from convinced that this is the best way to do this, but after several wasted hours, I'm just happy to have ANY way that works. I'm leaving this up in case it's either helpful for someone else, or someone knows a better way to get this working...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment