【问题标题】:Ember.js & Ember Data: How to create record with hasMany relationship when the parent and child don't exist yetEmber.js & Ember Data:当父子不存在时如何使用 hasMany 关系创建记录
【发布时间】:2014-03-25 20:31:58
【问题描述】:

就像我对 ember-data 所做的大多数事情一样,简单的测试用例非常简单,但由于我缺乏理解(我认为是文档),任何“真实”的东西都会很快分崩离析。在最简单的情况下,我可以毫无问题地创建新记录并将其保存到我的 REST API。我将使用流行的水果篮示例,并从保存一个新的fruit 开始。

// Here is our fruit model
module.exports = App.Fruit= DS.Model.extend({
    name: attr('string'),   
    color: attr('string')
});

// This is easy to create and save
var fruit = this.store.createRecord('fruit', {
    name: 'apple',
    color: 'red'
});

fruit.save().then(successCallback, errorCallback);

好的,我这里没问题。从概念上讲是有道理的,代码很干净,而且看起来很漂亮!现在假设我们有一个basket 模型并且basket 模型可以容纳很多fruit。此外,用户可以从 UI 一步创建新的fruit 并将其添加到尚未创建的新basket

以下是新模型:

module.exports = App.Fruit= DS.Model.extend({
    name: attr('string'),   
    color: attr('string')
    basket: DS.belongsTo('basket')
});

module.exports = App.Basket = DS.Model.extend({
    fruits: DS.hasMany('fruit', {async:true})
});

鉴于上述情况,假设用户在商店或后端 REST API 中当前不存在的两种新水果中输入,将它们添加到他的新购物篮(也尚不存在),然后点击'保存'。

您如何使用 Ember Data 创建此记录?我希望你能做这样的事情:

var newFruits = Ember.A();

newFruits.pushObject(this.store.createRecord('fruit', {
    name: 'orange',
    color: 'orange'
}));

newFruits.pushObject(this.store.createRecord('fruit', {
    name: 'banana',
    color: 'yellow'
}));

var basket = this.store.createRecord('basket', {
    fruits: newFruits
});

basket.save().then(successCallback, errorCallback);

不幸的是,这似乎不起作用。当我在 Chrome 检查器中查看 POST 请求数据时,篮子的 fruits 属性始终为空。基本上,请求最终看起来是这样的:

{
    basket: {
       fruits: []
    }
}

我是否使用正确的模式来创建“篮子”记录?我希望我不必在保存篮子之前先保存每块水果,因为当 1 个就足够时发送 3 个 POST 请求似乎很浪费。此外,当用户想要创建 10 个水果时会发生什么?那将是 11 个 POST 请求。

是否有完成上述操作的标准做法?本质上,您如何创建具有 hasMany 关系(篮子)的新记录,其中 hasMany 关系中的记录也是新的(水果)。

谢谢!

这是我正在使用的版本:

------------------------------- 
Ember      : 1.3.2+pre.25108e91 
Ember Data : 1.0.0-beta.7+canary.238bb5ce 
Handlebars : 1.3.0 
jQuery     : 2.0.3 
------------------------------- 

【问题讨论】:

    标签: ember.js ember-data


    【解决方案1】:

    我只是自己解决这个问题,但我就是这样做的,而且效果很好……

    对于初学者,当您 this.store.createRecord('basket', {}) 时,它的 fruits 属性应该带有一个空数组。所以,这样做:

    var basket = this.store.createRecord('basket', {});
    
    basket.get('fruits').addObject(this.store.createRecord('fruit', {
        name: 'orange',
        color: 'orange'
    }));
    
    basket.get('fruits').addObject(this.store.createRecord('fruit', {
        name: 'banana',
        color: 'yellow'
    }));
    

    顺便说一句,空的fruits 数组实际上是DS.PromiseArray(它可能会立即解析为DS.ManyArray?),是Ember.Array 的更具体的子类,因此可能会有所不同。

    但是,我发现fruits 属性根本不会被序列化——尽管我正在使用 JsonApiAdapter,所以 可能 是原因。或者,这可能是 hasMany 子对象尚未持久化时的预期行为。无论如何,我只是在控制器的 actions.save 方法中做了这样的事情:

    basket.save().then(function(){
        var promises = Ember.A();
        basket.get('fruits').forEach(function(item){
            promises.push(item.save());
        });
        Ember.RSVP.Promise.all(promises).then(function(resolvedPromises){
            alert('All saved!');
        });
    });
    

    不知何故,神奇地,当所有这些都完成后,我最终得到了一个保存的“篮子”,生成了id,并保存了“水果”,生成了ids。而且,所有水果的belongsTo 属性都指向篮子,篮子的hasMany 包含所有水果……尽管事实上,当我save()d 篮子时,我的后端的响应返回了一个空数组对于我的 fruits 属性,我确信它会搞砸,但不知何故没有。

    当然,这些不是我的实际模型,但相似度非常接近。我正在使用 Ember Data 1.0.0-beta5 和 Ember 1.3.1。我没有使用普通的 REST 适配器,但 JsonApiAdapter 是一个非常薄的外壳——所以试试这种方法,看看它是否有效!

    编辑

    我打开了一个similar question here,它解决了我在使用上述代码更新现有记录(而不是创建新记录)时遇到的问题。该解决方案更通用、更详细,但也更复杂。

    另外,我遇​​到的另一个潜在问题是,当(在此示例中)创建 basket 时,fruits 属性(即 DS.PromiseArray)可能还没有完全准备好。所以你可能需要这样做:

    var basket = this.store.createRecord('basket', {});
    
    basket.get('fruits').then(function(){
        // Now the fruits array is available
        basket.get('fruits').addObject(this.store.createRecord('fruit', { /* ... */ }));
    });
    

    【讨论】:

    • 很酷,谢谢!我实际上从我的代码中删除了 Ember Data,因为我厌倦了试图弄清楚它想要什么,但我把它保存在另一个分支中。将返回并尝试此解决方案,看看它是否有效。感谢分享! (会在这里告诉你进展如何)
    • @Sarus 请注意,我仍在弄清楚这在我的应用程序中是如何工作的。我已经尝试了大约一年了。新的 1.0.0-betaX Ember Data 构建现在可以更好地使用(阅读:实际上可能在示例之外工作),但它仍然很粗糙。我们为骑在最前沿所付出的代价。我将添加我发现必须进行的任何更改。
    • 保存篮子然后分别保存篮子中的每个项目后,这是否会导致您添加到“水果”数组中的每个“项目”的新 POST 请求,或者它是否以某种方式放置所有这些都放在一个 POST 请求中?
    • @Sarus 我观察到每个模型对象有一个发布请求。也就是说,在您的示例中,一个 POST 用于篮子,一个 POST 用于香蕉,一个 POST 用于橙子。我不确定是否有可能让 Ember Data 将它们全部一起发布,但我想有些人对如何(或不会)是“RESTful”有强烈的看法。无论如何,正如我在发布篮子时提到的那样,它甚至没有发送fruits 数组中水果的 ids (好吧,他们没有,所以怎么可能呢? ),所以我并不惊讶它没有发布对象。
    • @Sarus 确实,我想您至少应该能够发布篮子,然后一次性发布所有水果 - 这样您仍然可以发布所有单一类型的资源到单个端点,并且响应将仅包含一种类型的(主要)对象。但是,是的,这在 Ember Data 中可能还没有准备好,尽管老实说我不确定。鉴于我在这方面的历史,我很高兴能够“工作”,并且当它出现时我会采取“高效”:-)。
    【解决方案2】:

    如果其他人迟到,当前文档指出您可以像这样简单地调用createRecord()

    post.get('comments').createRecord({})

    即使post 是一个空对象,它仍然有效。

    【讨论】:

    • 当前文档在哪里?如何持久化(特别是如果在循环中创建多个?
    • 文档找到here。您基本上可以像store.createRecord 一样使用它,但您可以在关系数组上调用它,例如上面列出的comments。要坚持,你会像往常一样做newComment = post.get('comments').createRecord({}) 然后newComment.save()
    • 这个方法至少在 2.7.0 是私有的。
    猜你喜欢
    • 1970-01-01
    • 2012-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多