Search code examples
javascriptruby-on-railsbackbone.jsdeviserails-api

Override Backbone.sync for Rails API authentication with Devise


I am trying to override backbone's .sync method in order to have authentication working for my Rails API. I have been going off of this post and I feel like I am really close to figuring it out. I have the rails side set up but I am having trouble on the front end of things. I am stuck on the part in the other post where he has

var token = YourAppName.csrfToken;

I am not too sure what to substitute for 'YourAppName'. Here is the backbone code I have so far. My app is called 'Droppin' and when I sub it in I get errors saying it isn't defined.

// overide backbone.sync
Backbone._sync = Backbone.sync;

Backbone.sync = function(method, model, options) {
  if (!options.noCSRF) {
    var beforeSend = options.beforeSend;

    // Set X-CSRF-Token HTTP header
    options.beforeSend = function(xhr) {
      var token = Droppin.csrfToken;  
      if (token) xhr.setRequestHeader('X-CSRF-Token', token);

      // this will include session information in the requests
      xhr.withCredentials = true;

      if (beforeSend) return beforeSend.apply(this, arguments);
    };
  }

  var complete = options.complete;
  options.complete = function(jqXHR, textStatus) {

     // If response includes CSRF token we need to remember it
     var token = jqXHR.getResponseHeader('X-CSRF-Token') 
     if (token) Droppin.csrfToken = token;

     model.trigger('sync:end');
     if (complete) complete(jqXHR, textStatus);
  };

  // Serialize data, optionally using paramRoot
  if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
    options.contentType = 'application/json';
    data = JSON.stringify(options.attrs || model.toJSON(options));
    if (model.paramRoot) {
      data = {};
      data[model.paramRoot] = model.toJSON(options);
    } else {
      data = model.toJSON();
    }
    options.data = JSON.stringify(data);
  }

  return Backbone._sync(method, model, options);
};

What do I need to do in order to grab that CSRF token and have it properly attached to the HTTP header? I should also mention that I am using require.js and am handling the override in the main.js file (not sure if that is the right place to do it).


Solution

  • Have you defined Dropping somewhere else in your code beforehand? For example,

    window.Droppin = window.Dropping || {};
    

    If not, when you try to execute var token = Droppin.csrfToken; Droppin will be undefined and thus won't have the attribute csrfToken