2014-02-24 67 views
1

保存模型時,骨幹決定是否通過設置模型的ID屬性來發送HTTP POSTPUT請求。如果有一個ID,則認爲該模型已經存在。允許用戶在創建時指定骨幹模型的ID

對於我的應用程序,這種邏輯是不正確的,因爲我必須允許用戶指定一個ID(因爲我與一個設計不良的遺留系統交互)。

我應該如何處理這個問題?如果模型更改,我仍然想使用PUT

我正在考慮以下選項:

  1. 覆蓋isNew,這是簡單地檢查如果ID是本骨幹方法。
  2. 覆蓋sync
  3. 確定cid的概念是否能以某種方式解決問題。
+0

你應該考慮接受一個答案。 :) –

回答

0

這裏的另一種解決方案:

在模型中定義不存在於您的服務器型號/表中的idAttribute/...這將不會被顯示給DOM。

所以,讓我們假設您發送到服務器的JSON如下:

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

你的模型應該是這樣的:

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

現在,當你創建一個新的模型,並嘗試要將其保存到服務器,沒有人會初始化fakeId,並將其視爲新對象(PO​​ST)。

當你從服務器抓取你的模型,你必須設置fakeId在你的模型,你的服務器必須在fakeId你這樣的模式將被視爲現有(PUT)

+0

甜蜜的時機,因爲我現在自己處理這個問題。我不喜歡這個解決方案,因爲如果ID是可編輯的,你現在需要保持這兩個同步,你的服務器現在需要知道Backbone中的這個限制。不知道該修復應該是什麼,但它應該完全包含在Backbone中。 –

1

一個複製id解決辦法是解決症狀而不是原因。考慮添加到您的模型的新方法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困擾我,因爲我的用例(儘管工作和相當小),但也許它適用於你的。

我很想看到這個問題的一些額外的答案。

+0

也許你可以重載「保存」而不是添加「創建」。 –

+0

@DonaldTaylor但是那麼如何不對編輯執行POST覆蓋? –

1

所以我沿着試圖改變的路徑isNew

我想出了新的標準,從而回答模型是否是新的:

  1. 經一個創建的模型從集合取?然後它絕對不是新的。
  2. 使用ID屬性創建了模型嗎?這是我爲我的情況下做出了選擇,請參見下面這樣做的效果缺點,但我想讓new Model({ id: 1, name: 'bob' })不考慮新的,而以後(new Model({ name: bob'}).set('id', 1))將設置ID。
  3. 模型是否曾經同步過?如果模型在任何時候都成功同步,那肯定不是新的,因爲服務器知道它。

這裏是這個樣子:

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檢查,以解決這個問題,但後來從現有派生其數據的新模型的任何建設將被作爲新治療(在我的情況,這是不可取的)。