Last Updated: February 25, 2016
·
2.25K
· 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