22

Some of my Backbone models should always use POST, instead of POST for create and PUT for update. The server I persist these models to is capable of supporting all other verbs, so using Backbone.emulateHTTP is not a perfect solution either.

Currently I override the isNew method for these models and have it return true, but this is not ideal.

Other than modifying the backbone.js code directly, is there a simple way to achieve this goal on a model-by-model basis? Some of my models can use PUT (they are persisted to a different server that supports all verbs, including PUT), so replacing Backbone.sync with one that converts the 'update' method to 'create' is not ideal either.

aw crud
  • 8,791
  • 19
  • 71
  • 115
  • 2
    You can declare a `sync` method for your models that need POST instead of PUT and implement it locally on your models that way. You don't have to overwrite it for all models. Take a look at this answer on SO: http://stackoverflow.com/a/5096624/844726 – swatkins Dec 15 '11 at 22:51
  • 1
    Isn't this what [`Backbone.emulateHTTP`](http://documentcloud.github.com/backbone/#Sync-emulateHTTP) is for? – Roatin Marth Dec 16 '11 at 21:24

5 Answers5

56

For anyone who needs to force a POST/PUT request on the instance directly:

thing = new ModelThing({ id: 1 });
thing.save({}, { // options
    type: 'post' // or put, whatever you need
})
alxndr
  • 3,851
  • 3
  • 34
  • 35
15

Short and Sweet is put this on Top

Backbone.emulateHTTP = true;

This will use Get for Pull and Post for All pushes (read Create, Update, Delete)

Maanas Royy
  • 1,522
  • 1
  • 17
  • 30
8

add a sync(method, model, [options]) directly to your models you need to override.

YourModel = Backbone.Model.extend({
  sync: function(method, model, options) {
    //perform the ajax call stuff
  }
}

Here's some more information: http://documentcloud.github.com/backbone/#Sync

Yehuda Katz
  • 28,535
  • 12
  • 89
  • 91
Paul
  • 18,349
  • 7
  • 49
  • 56
5

the way I've done it is to override sync() thusly

Models.Thing = Backbone.Model.extend({
    initialize: function() {
        this.url = "/api/thing/" + this.id;
    },
    sync: function(method, model, options) {
        if (method === "read") method = "create";    // turns GET into POST
        return Backbone.sync(method, model, options);
    },
    defaults: {
        ...
Scott Evernden
  • 39,136
  • 15
  • 78
  • 84
4

I used a modification of Andres' answer and instead of havivng to remember to pass the option { type: 'post' } everywhere that I call .save() I instead just replaced the save function on the model to have it always add that option then call the base implementation. It felt cleaner...

module.exports = Backbone.Model.extend({
  idAttribute: 'identifier',
  urlRoot: config.publicEndpoint,

  save: function (attributes, options) {
    // because the 'identifier' field is filled in by the user, Backbone thinks this model is never new. This causes it to always 'put' instead of 'post' on save.
    // overriding save here to always pass the option use post as the HTTP action.
    options = _.extend(options || {}, { type: 'post' });
    return Backbone.Model.prototype.save.call(this, attributes, options);
  }
});
CodingWithSpike
  • 42,906
  • 18
  • 101
  • 138