Easily export Backbone-relational models

To export a Backbone-relational model we can extend the original Backbone-relational model with three attributes and an export method.

tl;dr, coffee version:

Backbone.ExportableModel = Backbone.RelationalModel.extend
  exportAttributes: []
  exportChildren: []
  exportSiblings: [] 
  export: ->
    data = {}
    if @exportAttributes.length
      data = @pick.apply @, @exportAttributes
    if @exportSiblings.length
      for sibling in @exportSiblings
        data[sibling] = @get(sibling).export() if @get(sibling)?
    if @exportChildren.length
      for child in @exportChildren
        data[child] = @get(child).invoke 'export'
    data  

Such a model will have an export() method, which will gather all exportAttributes values, go through exportChildren (aka has-many) and exportSiblings (aka has-one) relations and call the export() method on them. That produces a nice structured JSON as result.

For an example of such a model:

@App.M.FieldInstance = Backbone.ExportableModel.extend
  defaults: {}
  relations: [
    {
      type: Backbone.HasOne
      key: 'fieldInstanceImage'
      relatedModel: 'App.M.FieldInstanceImage'
      reverseRelation:
        includeInJSON: false
        type: Backbone.HasOne
        key: 'fieldInstance'
    }
  ]
  exportAttributes: ['type', 'width', 'height', 'x', 'y', 'points']
  exportSiblings: ['fieldInstanceImage']

To end with, I’ve included the compiled js version for non-coffee folk:

Backbone.ExportableModel = Backbone.RelationalModel.extend({
  exportAttributes: [],
  exportChildren: [],
  exportSiblings: [],
  "export": function() {
    var child, data, sibling, _i, _j, _len, _len1, _ref, _ref1;

    data = {};
    if (this.exportAttributes.length) {
      data = this.pick.apply(this, this.exportAttributes);
    }
    if (this.exportSiblings.length) {
      _ref = this.exportSiblings;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        sibling = _ref[_i];
        if (this.get(sibling) != null) {
          data[sibling] = this.get(sibling)["export"]();
        }
      }
    }
    if (this.exportChildren.length) {
      _ref1 = this.exportChildren;
      for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
        child = _ref1[_j];
        data[child] = this.get(child).invoke('export');
      }
    }
    return data;
  }
});