允许用户在创建时指定Backbone模型的ID

时间:2014-02-24 18:01:25

标签: javascript rest backbone.js

保存模型时,Backbone根据是否设置了模型的ID属性来确定是发送HTTP POST还是PUT请求。如果有ID,则认为该模型已存在。

对于我的应用程序,这个逻辑是不正确的,因为我必须允许用户指定一个ID(因为我与设计不良的遗留系统进行交互)。

我该如何处理这个问题?如果模型被更改,我仍然想使用PUT

我正在考虑以下选项:

  1. 覆盖isNew,这是一种只检查ID是否存在的Backbone方法。
  2. 覆盖sync
  3. 确定cid的概念是否会以某种方式解决问题。

3 个答案:

答案 0 :(得分:1)

一种解决方案是解决症状而不是原因。考虑向您的模型添加新的create方法:

var FooModel = Backbone.Model.extend({
  urlRoot: '/api/foo',
  create: function () {
     return this.save(null, { 
         type: 'post', // make it a POST rather than PUT
         url: this.urlRoot // send the request to /api/foo rather than /api/foo/:id
     });
  }
});

这是我使用的解决方案,但我不认为这是理想的,因为视图逻辑/调用者现在需要在创建时调用create而不是save(这很容易) 。这个扩展的API困扰我的用例(尽管工作和相当小),但也许它对你的用途。

我很想看到这个问题的其他答案。

答案 1 :(得分:1)

所以我走上了试图改变isNew的道路。

我提出了新的标准,可以回答模型是否是新的:

  1. 模型是通过集合中的提取创建的吗?那么它肯定不是新的。
  2. 是否使用ID属性创建了模型?这是我为我的案例做出的选择,请参阅下面的不利之处,了解这样做的效果,但我想让new Model({ id: 1, name: 'bob' })不能被视为新的,而稍后设置ID(new Model({ name: bob'}).set('id', 1))将是。
  3. 模型是否已同步?如果模型在任何时候都成功同步,那么它肯定不是新的,因为服务器知道它。
  4. 这是这样的:

    var UserDefinedIDModel = Backbone.Model.extend({
      // Properties
    
      _wasCreatedWithID: false,
      _wasConstructedByFetch: false,
      _wasSynced: false,
    
      // Backbone Overrides
    
      idAttribute: 'some_id',
    
      urlRoot: '/api/foo',
    
      constructor: function (obj, options) {
        this._wasCreatedWithID = !!obj[this.idAttribute];
        this._wasConstructedByFetch = options && options.xhr && options.xhr.status === 200;
    
        // Preserve default constructor
        return Backbone.Model.prototype.constructor.apply(this, arguments);
      },
    
      initialize: function () {
        this.on('sync', this.onSync.bind(this));
      },
    
      isNew: function () {
        // We definitely know it's not new
        if (this._wasSynced || this._wasConstructedByFetch) return false;
    
        // It might be new based on this.  Take your pick as to whether its new or not.
        return !this._wasCreatedWithID;
      },
    
      // Backbone Events
    
      onSync: function () {
        this._wasSynced = true;
      }
    });
    

    优于其他答案

    • 在处理这个奇怪用例的骨干模型之外没有逻辑。
    • 没有服务器端更改来支持此
    • 没有新的伪属性

    <强>缺点

    • 当你可以根据我的其他答案创建一个新的create方法时,这是很多代码。
    • 目前myCollection.create({ some_id: 'something' });发出PUT。我想如果您需要支持,则必须执行myCollection.create({ some_id: 'something' }, { url: '/api/foo', type: 'post' });您可以删除_wasCreatedWithoutID检查以解决此问题,但是从现有模型中获取数据的任何新模型构造都将被视为新的(就我而言,这是不可取的)。

答案 2 :(得分:0)

这是另一种解决方案:

在你的模型中定义一个idAttribute,它在你的服务器模型/ table / ...中不存在,并且不会显示给DOM。

因此,假设您发送到服务器的JSON如下:

{
    'id': 1,
    'name': 'My name',
    'description': 'a description'
}

您的模型应如下所示:

var MyModel = Backbone.Model.extend({
    idAttribute: 'fakeId'
});

现在,当您创建新模型并尝试将其保存到服务器时,没有人会初始化fakeId,它将被视为新对象(PO​​ST)。

当您从服务器获取模型时,您必须在模型中设置fakeId,并且您的服务器必须复制id中的fakeId,因此您的模型将被视为现有模型( PUT)