Ember Data: сохранение отношений
Мне нужно сразу сохранить глубокий объект на сервере и не смогли найти примеры в Интернете, в которых используются последние данные ember (1.0.0-beta.4).
Например, с этими моделями:
(jsfiddle)
App.Child = DS.Model.extend({
name: DS.attr('string'),
age: DS.attr('number'),
toys: DS.hasMany('toy', {async:true, embedded:'always'}),
});
App.Toy = DS.Model.extend({
name: DS.attr('string'),
child: DS.belongsTo('child')
});
И этот код:
actions: {
save: function(){
var store = this.get('store'),
child, toy;
child = store.createRecord('child', {
name: 'Herbert'
});
toy = store.createRecord('toy', {
name: 'Kazoo'
});
child.set('toys', [toy]);
child.save();
}
}
Он сохраняет JSON только для дочернего объекта, но не для каких-либо игрушек, даже не загруженных:
{
child: {
age: null
name: "Herbert"
}
}
Нужно ли вручную сохранять игрушки? В любом случае, я могу отправить его на сервер следующего JSON:
{
child: {
age: null
name: "Herbert",
toys: [{
name: "Kazoo"
}]
}
}
или
{
child: {
age: null
name: "Herbert",
toys: [1]
}
}
См. JSFiddle: http://jsfiddle.net/jgillick/LNXyp/2/
Ответы
Ответ 1
Мне нужен был глубокий объект, а не боковое, поэтому, основываясь на ответе kingpin2k, я придумал следующее:
DS.JSONSerializer.reopen({
serializeHasMany: function(record, json, relationship) {
var key = relationship.key,
property = Ember.get(record, key),
relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship);
if (property && relationshipType === 'manyToNone' || relationshipType === 'manyToMany' ||
relationshipType === 'manyToOne') {
// Add each serialized nested object
json[key] = [];
property.forEach(function(item, index){
json[key].push(item.serialize());
});
}
}
});
Теперь, когда вы вызываете child.serialize()
, он вернет этот объект:
{
child: {
name: "Herbert",
toys: [
{
name: 'Kazoo'
}
]
}
}
Это то, что мне нужно. Здесь jsfiddle с ним в действии: http://jsfiddle.net/jgillick/LNXyp/8/
Ответ 2
Ответы здесь устарели. Ember Data теперь поддерживает встроенные записи, что позволяет делать именно то, что вы хотите сделать, чтобы получить и отправить полный граф объектов в одну большую полезную нагрузку. Например, если ваши модели настроены следующим образом:
App.Child = DS.Model.extend({
name: DS.attr('string'),
age: DS.attr('number'),
toys: DS.hasMany('toy')
});
App.Toy = DS.Model.extend({
name: DS.attr('string'),
child: DS.belongsTo('child')
});
Вы можете определить собственный сериализатор для вашей модели Child:
App.ChildSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
toys: {embedded: 'always'}
}
});
Это говорит Ember Data, что вы хотите, чтобы "игрушки" были включены как часть "детской" полезной нагрузки. Ваш ответ HTTP GET из вашего API должен выглядеть следующим образом:
{
"child": {
"id": 1,
"name": "Todd Smith",
"age": 5,
"toys": [
{"id": 1, "name": "boat"},
{"id": 2, "name": "truck"}
]
}
}
И когда вы сохраните свою модель, Ember Data отправит ее на сервер:
{
"child":{
"name":"Todd Smith",
"age":5,
"toys":[
{
"id":"1",
"name":"boat",
"child":"1"
},
{
"id":"2",
"name":"truck",
"child":"1"
}
]
}
}
Вот JSBin, который демонстрирует это.
http://emberjs.jsbin.com/cufaxe/3/edit?html,js,output
В JSbin, когда вы нажимаете кнопку "Сохранить", вам необходимо использовать Dev Inspector для просмотра запроса, отправленного на сервер.
Ответ 3
игрушки не могут быть как асинхронными, так и встроенными всегда, это противоречивые варианты. Embedded существует только в активном сериализаторе модели.
toys: DS.hasMany('toy', {embedded:'always'})
игрушки - это отношения ManyToOne, и поскольку отношения существуют на стороне whoTo, более эффективно сохранять отношения во время сохранения игрушки. При этом, если вы создаете его все сразу, то хотите сохранить его в одном большом куске, когда вступает в игру переопределение.
serializeHasMany: function(record, json, relationship) {
var key = relationship.key;
var relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship);
if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany' ||
relationshipType === 'manyToOne') {
json[key] = get(record, key).mapBy('id');
// TODO support for polymorphic manyToNone and manyToMany relationships
}
},
И ваше сохранение должно быть таким:
var store = this.get('store'),
child, toy;
child = store.createRecord('child', {
name: 'Herbert'
});
toy = store.createRecord('toy', {
name: 'Kazoo'
});
child.get('toys').pushObject(toy);
child.save().then(function(){
toy.save();
},
function(err){
alert('error', err);
});