Dark Knight
Dark Knight

Reputation: 503

Backbone sync issue firing POST instead of PUT

I have written the following code in my model:

 urlroot: '/url/sms',
setAuthId: function(value) {

    var _this = this ;

     if (this.get("smsauth") != value) {

        this.set("smsauth",value);
        this.save();

//Ideally, I want to achieve this AJAX call request with backbone.

         // $.ajax({
         //     url: "/url/sms",
         //     data: value,
         //     type: 'PUT',
         //     processData: false,
         //     success: function(result) {
         //        _this.set("authId", value);

         //     },
         //    error : function(){
         //        console.log('Error setting authid');
         //    }
         // });
     }

 },

Ideally, we should be firing a "PUT" request everytime. But the backbone is firing a POST request because "ID" is not present.

I'm quite new to backbone, I was wondering if there is anyway to sync with server without having to pass an ID? How can I solve this problem? I basically want to fire a PUT request NOT post request for the URL. (Since my backend only supports PUT request).

Upvotes: 2

Views: 344

Answers (4)

Dark Knight
Dark Knight

Reputation: 503

I have used this snippet.

this.save({}, {
  type: 'PUT'
});

I found all your answers really fascinating, I am going to try everyone of them.

Thanks for your suggestions, this is why I like SO. Something new to learn.

Upvotes: 2

seebiscuit
seebiscuit

Reputation: 5063

The only real way to force Backbone.Model.save() to do a PUT is the way @dbf explained, you have to set your idAttribute. To properly set idAttribute your model should have an attribute that is unique. (This is not a hard requirement, since model.isNew() just checks that your model has a property named id or whatever string you supply to your model idAttribute property. It doesn't check for uniqueness).

I sense that in your case, you may not have a unique attribute in your models, so setting idAttribute may be a challenge. For that reason, I suggest you don't specify an idAttribute in your model definition. Rather, we just handle it dynamically.Just refactor your code like this:

setAuthId: function(value) {
    var _this = this ;

     if (this.get("smsauth") != value) {
        // any model attribute is fine, we just need to return a prop
        this.prototype.idAttribute = "smsauth" 
        this.save("smsauth",value) // Save will do a set before the server request
         // model.save returns a promise. Here we'll reset the idAttribute
         .then(/* success handler */ function (response) { 
             _this.set("authId",value);
             _this.prototype.idAttribute = 'id' // You can set this to "authId" if that 
                                                // uniquely identifies this model
         },/* error handler */  function (response) { 
             _this.prototype.idAttribute = 'id' // reset idAttribute to default
         });
     }
}

Upvotes: 3

dbf
dbf

Reputation: 3463

It's not really clear to me what you are saving. The fact you are handling with POST suggest its a new entry. Quoting from the docs this behaviour is correct. PUT is update, POST is create (under CRUD operations).

If the model isNew, the save will be a "create" (HTTP POST), if the model already exists on the server, the save will be an "update" (HTTP PUT).

What you might try is what @Sami suggest by overwriting the save with an update request (do realise that all solutions here are incorrect/workarounds).

If you really need PUT and cannot alter your backend for some mysterious reason to accept POST, you could change the idAttribute within the model.

var smsModel = Backbone.Model.extend({
   idAttribute: "smsauth" // for example
});

Do realise that your backend, very likely, has a design flaw where you are changing and creating workarounds to work with it, which you should consider to avoid.

Upvotes: 2

Sami
Sami

Reputation: 4006

You can override save method. Something like

   var model = Backbone.Model.extend({

         save: function(options){
             return Backbone.sync("update", this, options);
         }


   });

Upvotes: 0

Related Questions