对Ember Data的多对多关系进行增量更改

时间:2014-11-08 16:50:04

标签: ember.js ember-data

在我的网络应用程序中,我有产品和购物清单。服务器提供REST端点。

GET /api/shopping-lists/abc

返回

{
  shoppingList: {
    id: "abc",
    products: ["p123", "p234", "p345"]
  }
}

在我的Ember 1.7.0应用程序中,我使用Ember Data 1.0.0-beta.6。我的模型看起来像这样:

App.ShoppingList = DS.Model.extend({
    products: DS.hasMany("product", {async: true}),
});

App.Product = DS.Model.extend({
    name:  DS.attr("string")
});

因为我无法找到正确的信息" Ember way"添加和删​​除多对多关系中的记录,我正在这样的购物清单中添加和删除产品:

function addToShoppingList(shoppingList, toBeAddedProduct) {

    shoppingList.get("products").then( function(products) {
        products.pushObject( toBeAddedProduct );
        shoppingList.save();
    });

}


function removeFromShoppingList(shoppingList, toBeRemovedProduct) {

    shoppingList.get("products").then( function(products) {
        products.removeObject( toBeRemovedProduct );
        shoppingList.save();
    });

}

在上面的函数调用shoppingList.save()时,Ember数据将发送一个PUT请求,其中包含JSON有效内容,其中包含此购物清单中所有产品的ID:

addToShoppingList(abcShoppingList, p456Product);

//results in PUT on /api/shopping-lists/abc with payload:
{
    "shoppingList" : {
        "products" : ["p123", "p234", "p345", "p456"]
    }
}

由于购物清单可能会变长,我宁愿只有一个增量更新,只包含购物清单的更改,即:

{
    "shoppingList" : {
        "products" : ["p456"]
    }
}

我可以将Ember数据仅用于PUT对记录的更改,而不是发送完整记录吗?

此外,removeFromShoppingList(..)功能会将完整记录作为 PUT 请求发送。相反,我希望让它发送增量DELETE 请求。

1 个答案:

答案 0 :(得分:1)

Ember Data允许您在适当的模型序列化器中以及适配器(如果需要)中实现构建json有效负载所需的任何内容。我建议查看JSONSerializer和RESTSerializer的Ember Data源代码,因为调整生成(序列化)和消耗(规范化)的JSON有很大的灵活性。

听起来你想要实现PATCH语义,但你可以用PUT做你想要的,只提供你的URL端点目标产品关系,例如/api/shopping-lists/123/products。这与定位完整模型/api/shopping-lists/123和PUTing仅仅是“products”数组不同,因为它不符合HTTP语义。

URL标识资源,并且该端点上的GET和PUT或DELETE可以幂地更新或删除单个属性甚至是值的子集,只要URL范围指向该属性或某个子集,它就是定义一个独特的资源,HTTP完全支持重叠资源,甚至多个资源受到PUT的影响。

因此,您可以将购物清单中的产品表示为单独的资源:/api/shopping-lists/123/:product-id,只需使用DELETE删除和PUT即可创建/添加产品到列表中。许多URL设计都是可能的,包括如图所示的嵌套URL或使用复合键甚至代理键的URL,因此您必须考虑在您的服务器上最有效的方法。

您可以决定实施Ember数据连接模型,例如ShoppingListProduct,以便更轻松地管理。然后,ShoppingListProduct将为ShoppingList和Product指定belongsTo关系。您还可以从belongsTo关系生成'id'属性,以便DS Store标识映射按预期工作。在模型序列化器中实现这一点非常简单。

<强>更新

要在下面回答你的评论,遵循的一个好规则是将PUT视为REPLACE而不是UPDATE,这样你PUT就是你应该得到的东西,假设你的PUT没有其他任何东西修改了资源。如果这不是真的,那么可能表明您没有在URL上定义足够精细的粒度来确定要替换的内容,或者您​​可能应该考虑使用PATCH来仅定位您想要更改的属性。

我不知道本身是否存在“最佳实践”但我倾向于仅从具有外键的端点(即belongsTo端)更新资源。我通常最终得到一个加入资源,例如Taggings或Friendship,所以它只是通过belongsTo管理关系。这往往遵循您在关系数据库中的操作,因此它运行良好。