Данные Ember: модель и подмодели hasMany не сохраняются

У меня проблема, похожая на этот вопрос о переполнении стека, за исключением того, что ответ, похоже, не работает. У меня есть форма, в которой пользователь создает модуль-контейнер с переменным количеством подмоделей. Когда форма отправлена, я должен сохранить контейнер, подмодели и убедиться, что отношение hasMany сохраняется. Мой код (с использованием Ember-Cli):

контейнер:

var Container= DS.Model.extend({
    name: DS.attr('string'),
    submodels: DS.hasMany('submodel'),
    lastModified: DS.attr('date')
});

export default Container;

подмодель:

    var Submodel= DS.Model.extend({
        char: DS.belongsTo('container'),
        name: DS.attr('string'),
        desc: DS.attr('string'),
        priority: DS.attr('number'),
        effort: DS.attr('number'),
        time: DS.attr('number')
    });

export default Submodel;

ContainersNewRoute:

 export default Ember.Route.extend({
        model: function() {
            return this.store.createRecord('container', {
                ...
            });
        }
    });

ContainersNewController:

export default Ember.ObjectController.extend({
    actions: {
        addSubmodel: function() {
            var submodels= this.get('model.submodels');

            submodels.addObject(this.store.createRecord('submodel', {
                ...
            }));
        },
        saveNewContainer: function () {
            var container = this.get('model');

            container.save().then(function(){
                var promises = Ember.A();
                container.get('submodels').forEach(function(item){
                    promises.push(item.save);
                    console.log(item);
                });
                Ember.RSVP.Promise.all(promises).then(function(resolvedPromises){
                    alert('all saved');
                });
            });

            this.transitionToRoute(...);
        }
    }
});

Сами Ember Data работают нормально, переход к представлению созданного контейнера с перечислением подмоделей. Обновите страницу, и подмодели исчезнут из представления контейнера.

Я пробовал несколько вариантов, например, используя pushObject, а не addObject из ответа на переполнение стека. Я также пытался использовать обратный вызов Ember.RSVP для запуска container.save() во второй раз после сохранения подмоделей.

После некоторого дальнейшего тестирования я обнаружил, что подмодели вообще не сохраняются.

Есть ли разумный способ сохранить 1) контейнер 2) подмодели 3) отношения hasMany/belongsTo друг к другу?

Или это каким-то образом нужно разбить на отдельные шаги, где я сохраняю контейнер, сохраняю подмодели, помещаю подмодели в контейнер, чтобы получить отношение hasMany и повторно сохранять контейнер, и, наконец, сделать подмодели принадлежащими контейнеру и сохранить опять подмодели?


person ansorensen    schedule 13.06.2014    source источник
comment
Не могли бы вы обозначить экспортированные маршруты/контроллеры? Трудно угадать, как вещи связаны, когда вы просто получаете экспорт. Спасибо!   -  person Kingpin2k    schedule 14.06.2014
comment
Не могли бы вы также включить определения моделей?   -  person Kingpin2k    schedule 14.06.2014


Ответы (2)


Эта проблема

По умолчанию DS.hasMany в ассоциации "один ко многим" не будет включать поле ids при сериализации. Вы можете использовать DS.EmbeddedRecordsMixin, чтобы изменить это поведение.

Больше информации

Пожалуйста, прочтите раздел Миксины встроенных записей в Подробном руководстве по Ember Data для получения дополнительной информации. (отказ от ответственности, я его автор.)

Вот отрывок

DS.EmbeddedRecordsMixin — это расширение для DS.ActiveModelSerializer, которое позволяет настроить сериализацию или десериализацию ассоциаций. Хотя она еще не завершена (особенно в отношении полиморфных ассоциаций), тем не менее она интригует.

Ты можешь выбрать:

  • Не сериализовать или десериализовать ассоциации.
  • Чтобы сериализовать или десериализовать ассоциации с идентификатором или идентификаторами.
  • Для сериализации или десериализации ассоциаций со встроенными моделями.

Пример кода:

App.CartSerializer = DS.ActiveModelSerializer
                       .extend(DS.EmbeddedRecordsMixin)
                       .extend{
                         attrs: {
                           items: {serialize: 'ids', deserialize: 'ids'}
                         }
                       });

App.Cart = DS.Model.extend({
  items: DS.hasMany('item', {async: true})
});

App.Item = DS.Model.extend({
  cart: DS.belongsTo('item', {async: true})
});
person Pooyan Khosravi    schedule 23.06.2014

У вас есть проблема, с которой я столкнулся ранее, у вас есть более простой пример, чем у меня, потому что вам нужно только одно отношение: hasMany и: belongsTo

Попробуйте использовать этот подход:

export default Ember.ObjectController.extend({
// here we can pre-load submodels container, 
//even if it's empty because 'this.get('model.submodels')' returns promise

submodels: function () { 
    return this.get('model.submodels');
}.property('[email protected]'),

actions: {
    addSubmodel: function () {
        //saving context of controller, saving container for 
        //better understanding (clear vision)
        var controller = this, 
            container = controller.get('conrtainer');
        //container  instead of 'model' for better understanding :)

        //1. Creating submodel
        var submodel = this.get('store').createRecord('submodel', {
            // ... //
            container: container
        });

        //2. Saving submodel
        submodel.save().then(function (submodel_res) {

            //3. It isn't the end though :) 
            //Now we're getting our submodels from the container - here we will get
            //the result instead of promise, remember we pre-loaded it :) -1 nesting lvl
            controller.get("submodels").pushObject(submodel_res);

            //4. Now we need to update our 'parent' model - Container
            container.save().then(function (post_res) {
                console.log(post_res); // 5. Doesn't matter we are happy
            }, function (err) {
                console.log(err);
            });
        }, function (err) {
            console.log(err);
        });
      }
   }
});

 //In order to use this approach you need to override property 
 //in model serializer (just copy it    and //paste :) )

 YourApp.ContainerSerializer = DS.ActiveModelSerializer.extend({ 
 // here coulbe be RESTSerializer as well ;)

 primaryKey: function () {
    return '_id';
 }.property(), 
 // it's just helpful tip, if you use mongo like me ;) 
 //it doesn't relates to the main topic itself

 // this little method will help you update 'parent' model ;)
 serializeHasMany: function (record, json, relationship) { 
    var key = relationship.key;
    var json_key = key.singularize().decamelize() + '_ids';

    var relationshipType = DS.RelationshipChange.determineRelationshipType(
        record.constructor, relationship);

    if (relationshipType === 'manyToNone' 
    || relationshipType === 'manyToMany' 
    || relationshipType === 'manyToOne') {
        json[json_key] = Ember.get(record, key).mapBy('id');
    }
 }
});

Удачи ;)

person Blackening    schedule 14.07.2014