调用myModel.save()返回过时的模型 [英] Calling myModel.save() Returning Outdated Model
问题描述
我正在尝试在更新后保存Ember Data DS.Model
,但是当我调用 myModel.save()
,我发现Ember Data正在发送原始的,未更新的模型,而不是更新的模型。我想了解为什么会发生这种情况,我需要做的不同。
这里有一些细节。首先,我有两个模型:
/models/OrgUser.js:
DS.Model.extend({
...
orgPerson:DS.belongsTo('org-person',{inverse:'org-user',async :true,embedded:'always'}),
});
请注意,我使用自定义的 RESTSerializer
(见下文),所以唯一使用嵌入的:'always'
是我的自定义 RESTSerializer
处理它的方式。 / p>
/models/OrgPerson.js:
DS.Model.extend({
...
orgUser:DS.belongsTo('org-user'),
})
要保留这些模型,我使用的是 RESTAdapter
。为了生成包含上述两个模型的我的API的单个JSON请求,我已经对适配器进行了单一的自定义。我不认为这是什么影响,但是为了防止我错过了一些事情,这里是:
/serializers/application.js: / strong>
DS.RESTSerializer.extend({
serializeBelongsTo:function(record,json,relationship){
var key = relationship.key;
key = this.keyForRelationship?this.keyForRelationship(key,'belongsTo'):key;
var data = record.get('data ');
if(relationship.options.embedded&& relationship.options.embedded ==='always'){
json [key] = data [relationship.key] ?data [relationship.key] .get('data'):null;
}
else {
json [key] = data [relationship.key]?data [relationship.key] .get('id'):null;
}
if(relationships.options.polymorphic){
this.serializePolymorphicType(record,json,relationship);
}
}
})
使用该设置,我有一个更新orgPerson属性的模板。我可以确认这些是绑定的属性,因为更新他们的输入实时更新他们的显示在模板的另一部分。然后我在控制器上调用一个动作
,并在该操作中执行以下操作:
/ controllers /my-page.js:
导出默认Ember.ObjectController.extend(FormMixin,{
操作:{
submitForm:function(){
...
this.get('model')// Chrome控制台显示_data.orgPerson._data.firstName具有(不正确)旧的属性
this.get('model')。serialize()//返回(不正确)old firstName
this.get('orgPerson.firstName')//返回(正确)更新firstName
this.get('orgPerson')。get('firstName')//返回(正确)更新firstName
...
}
}
});
任何想法为什么我得到两个不同版本的同一机型?如何序列化正确更新的模型?感谢任何输入!
解决方案:
感谢(再次!)到@ kingpin2k,解决了这个问题。以下是我采取的步骤:
- 我的串行器实际上是问题,并使用Ember的旧保留数据。我将行
data [relationship.key] .get('data')
替换为行data [relationship.key] .serialize()
,这是固定的。 - 然后遇到另一个问题,那就是如果我编辑我的记录,没有保存,然后回到我的列表的记录,列表仍然显示编辑。我的第一个想法是,我需要更新我的列表页面的数组
模型
来仅显示最新的内容,但似乎没有任何Ember的设施。 li>
- 所以我最终通过在我的路由中使用以下代码来解决这个问题。请注意,因为
orgPerson
是async:true
我不得不将我的模型包裹在一个承诺中。还要注意,我不得不直接调用model.orgPerson
而不是仅仅模型
。
更新的路线:
actions:{
willTransition:function(transition){
this.controller.get('model.orgPerson')。then(function(value){
if (value.get('isDirty')){
value.rollback();
}
});
}
}
- 只需要调用
this.controller.get('model')。rollback()
,所以我要编写一个通过eachRelationship
,然后在任何对象上单独调用rollback()
。呃,很多细微的,让这个工作正常。
数据
obj中的值。它将修改后的值存储在 _attributes
obj中。在保存期间,将$ code> _attributes obj移动到FlightAttributes obj中的中,然后在保存完成后,将它们从
inFlightAttributes
到数据
。所有这一切都是您可以回滚您的记录。
当您将属性定义为 attr
时,它会将魔术获取起始位置 _attributes
,然后 inFlightAttributes
,然后 data
并返回该属性的结果。 >
function getValue(record,key){
if(record._attributes.hasOwnProperty(key)){
return record._attributes [键]。
} else if(record._inFlightAttributes.hasOwnProperty(key)){
return record._inFlightAttributes [key];
} else {
return record._data [key];
}
}
在你的情况下,Ember Data不知道您正在保存该记录,并且您正在从数据
obj手动抓取旧属性。您需要手动将 _attributes
合并到数据
,或者将Ember Data视为保存它。 / p>
I am attempting to save an Ember Data DS.Model
after it's been updated, but when I call myModel.save()
, I'm finding that Ember Data is sending the original, non-updated model instead of the updated one. I'm trying to understand why this is happening and what I need to do differently.
Here are some details. First, I have two models:
/models/OrgUser.js:
DS.Model.extend({
...
orgPerson: DS.belongsTo('org-person', { inverse: 'org-user', async: true, embedded: 'always' }),
});
Note that I am using a customized RESTSerializer
(see below), so the only use of embedded: 'always'
is how my custom RESTSerializer
handles it.
/models/OrgPerson.js:
DS.Model.extend({
...
orgUser: DS.belongsTo('org-user'),
})
To persist these models, I'm using the RESTAdapter
. In an attempt to generate a single JSON request to my API that contains both models above, I've made a single customization to the adapter. I don't think this is affecting anything, but just in case I'm missing something, here it is:
/serializers/application.js:
DS.RESTSerializer.extend({
serializeBelongsTo: function(record, json, relationship) {
var key = relationship.key;
key = this.keyForRelationship ? this.keyForRelationship(key, 'belongsTo') : key;
var data = record.get('data');
if (relationship.options.embedded && relationship.options.embedded === 'always') {
json[key] = data[relationship.key] ? data[relationship.key].get('data') : null;
}
else {
json[key] = data[relationship.key] ? data[relationship.key].get('id') : null;
}
if (relationship.options.polymorphic) {
this.serializePolymorphicType(record, json, relationship);
}
}
})
With that setup, I have a template where I update the orgPerson properties. I can confirm these are bound properties because updating their input updates their display on another part of the template in real-time. I then call an action
on my controller, and within that action do the following:
/controllers/my-page.js:
export default Ember.ObjectController.extend( FormMixin, {
actions: {
submitForm: function() {
...
this.get('model') // Chrome console shows that _data.orgPerson._data.firstName has the (incorrect) old property
this.get('model').serialize() // returns (incorrect) old firstName
this.get('orgPerson.firstName') // returns (correct) updated firstName
this.get('orgPerson').get('firstName') // returns (correct) updated firstName
...
}
}
});
Any idea why I am getting two different versions of the same model? How can I serialize the correctly updated model? Thanks for any input!
SOLUTION:
Thanks (again!) to @kingpin2k, I have resolved this issue. Here are the steps I took:
- My serializer was in fact the problem, and using Ember's old preserved data. I replaced the line
data[relationship.key].get('data')
with the linedata[relationship.key].serialize()
and this was fixed. - I then ran into another issue, which was that if I edited my record, did NOT save it, and then went back to my list of records, the list still showed the edit. My first thought was that I needed to update my list page's array
model
to show only the latest content, but there didn't appear to be any Ember facilities for this. - So I ultimately solved this by using the following code in my route. Note that because
orgPerson
isasync: true
I had to wrap my model in a promise. Note also that I had to directly callmodel.orgPerson
versus justmodel
.
Updated route:
actions: {
willTransition: function( transition ) {
this.controller.get('model.orgPerson').then( function( value ) {
if ( value.get('isDirty') ) {
value.rollback();
}
});
}
}
- Going forward, I just want to call
this.controller.get('model').rollback()
, so I'm going to write a util function that traverseseachRelationship
and then individually callsrollback()
on any of the objects. Whew, a lot of subtlety to get this working right.
Ember Data stores the original values in the data
obj. It stores modified values in _attributes
obj. During a save it moves _attributes
obj to inFlightAttributes
obj, then after the save is complete it merges them from inFlightAttributes
to data
. All of this is so you can rollback your record.
When you define a property as attr
it hooks up the magical get where it first checks _attributes
, then inFlightAttributes
, then data
and returns that property's result.
function getValue(record, key) {
if (record._attributes.hasOwnProperty(key)) {
return record._attributes[key];
} else if (record._inFlightAttributes.hasOwnProperty(key)) {
return record._inFlightAttributes[key];
} else {
return record._data[key];
}
}
In your case, Ember Data doesn't know you are saving that record, and you are manually grabbing the old properties from the data
obj. You'd either need to manually merge _attributes
to data
or trick Ember Data into thinking you'd saved it.
这篇关于调用myModel.save()返回过时的模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!