Last Updated: February 25, 2016
·
2.523K
· jho406

Add paramRoot support for your Rails Backbone app

Out of the box, Backbone doesn't include a param root by default when sending requests off to your rails app.

There are gems like backbone-rails that offer some syntactic sugar with a paramRoot feature.

var User = Backbone.Model.extend({
   paramRoot: 'user'
});

Which lets you do

User.new(params[:user])

in your controllers.

But here's a lighter way to add paramRoot sugar support:

Backbone.sync calls toJSON() when it sends data off to your app. The method is pretty bare, but it gets passed an options object. So well just make it a little smarter and pass it a indicator if it wants to wrap everything in a param root:

_.extend(Backbone.Model.prototype, {
  //override backbone json
  toJSON: function(options) {
    var data = {},
        attrs = _.clone(this.attributes);
    //if the model has a paramRoot attribute, use it as the root element
    if(options && options.includeParamRoot && this.paramRoot) {
      data[this.paramRoot] = attrs;
    } else {
      data = attrs;
    }

    return data;
  }
});

Additionally, we'll override Backbone.sync so it'll automatically pass an includeParamRoot indicator to toJSON() on create, update, and patch:

//store the old sync, this is to make testing easier.
Backbone.oldSync = Backbone.sync;

//replace backbone sync with our own version.
Backbone.sync = function( method, model, options ) {

  //pass in a includeParamRoot = true to the options
  if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
    options.includeParamRoot = true;
  }

  return Backbone.oldSync.apply(this, [method, model, options]);
};

Here's the finished product:

//Smarter JSON, we overwrite sync to keep rails convention of having a root
//to requests.
!function(Backbone){
  //store the old sync, this is to make testing easier.
  Backbone.oldSync = Backbone.sync;

  //replace backbone sync with our own version.
  Backbone.sync = function( method, model, options ) {

    //pass in a includeParamRoot = true to the options
    if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
      options.includeParamRoot = true;
    }

    return Backbone.oldSync.apply(this, [method, model, options]);
  };

  _.extend(Backbone.Model.prototype, {
    //override backbone json
    toJSON: function(options) {
      var data = {},
          attrs = _.clone(this.attributes);
      //if the model has a paramRoot attribute, use it as the root element
      if(options && options.includeParamRoot && this.paramRoot) {
        data[this.paramRoot] = attrs;
      } else {
        data = attrs;
      }

      return data;
    }
  });

}(Backbone);

Have a fresh tip? Share with Coderwall community!

Post
Post a tip
Did you know?

JavaScript on a page runs with the privileges of that origin. One altered library, tag manager, or snippet can read inputs, change what people see, and call your APIs as the user.

Security insights from Cside