Ember:创建模型的 DS.belongsTo *外部*

Ember: create a DS.belongsTo *outside* of a Model

我想在我自己的 class 中理想地创建一个 DS.belongsTo / BelongsToRelationship(这是一个 Ember.Object,但不是 DS.Model ),或者重新创建功能,让我在自己的 class 中保留对记录的引用。我不知道是否可以在 DS.Model 之外使用 DS.belongsTo,或者如果可以,如何设置它。

背景:

我有一个使用 ember-data + ember-fire + firebase 的 ember-cli 应用程序。我的一个模型有一个属性,它是一个保存“类型特定”信息的对象。我根据它描述的 type 将这个对象转换为我自己的 class ,有时该类型会引用数据库中的其他记录。在这些情况下,我想在我的 typeSpecific class 中设置一个 DS.belongsTo 属性,我可以 link 以与 linking 中的关系相同的方式常规型号。

选择:

经过大量搜索,但没有找到任何有关如何执行此操作的信息,我自己制作了 class,这让我完成了大部分工作。我刚刚注意到,虽然我可以更改它在客户端引用的记录并更新它,但如果我在服务器端更改它,我就不会收到更新,所以它又回到了绘图板。

如果有人能告诉我如何使这种替代方法起作用也能达到目的。这个 class 的想法是我将模型名称和 ID 传递给它,它应该创建模型引用,然后在任何一方发生变化时保持 modelid 同步,并且如果连接到的模型上的任何内容发生更改,就像常规关系一样,则通过更新。

export default Ember.Object.extend({

  id: null,
  table: undefined,
  model: undefined,
  store: undefined,

  init: function() {
    this._super();
    if(this.id && !this.model) {
      this.updateModel();
    }
    else if(this.model && !this.id) {
      this.updateId();
    }
  },

  updateModel: function() {
    var self = this;
    if( this.get('id') ) {
      this.store.find(this.get('table'), this.get('id')).then( function(model) {
         self.set('model', model);
      });
    }
    else {
      self.set('model', undefined);
    }
  }.observes('id','table'),

  updateId: function() {
    if(this.get('model')) {
      this.set('id', this.get('model.id'));
    }
    else {
      this.set('id', null);
    }
  }.observes('model'),
});

编辑:操作上面对象的代码:

//Creating a reference:
this.set('target', ModelPointer.create({store:this.get('store'), table:this.get('targetTable'), id:targetId}));

//or:
this.set('target', ModelPointer.create({store:store, table:'myTable'}));
...
this.set('target.id', '42');

我相信目前如果我在客户端上更改 idmodel,另一个会自动更新,例如:

//either:
this.set('target.id', '43');
//or:
this.store.find('myTable','43').then( function(newModel) {
  self.set('target.model', newModel);
});

问题是,如果我登录 Firebase 并更改 myTable['42'].name='Fred',那么我网页上显示的 link 编辑为 target.model.name 的值不会更新为 'Fred'。我怀疑如果我在客户端将 target.model.name 设置为 'Fred' 并保存它也不会更新服务器上的值(?)

我想出的最干净的解决方案是不单独存储 id(留给模型本身)。我已经验证我在 Firebase 中所做的更改会很好地传播到显示的条目。

通过此解决方案设置,可以使用其 id 或简单地使用模型实例本身来完成引用模型。有关示例,请参阅控制器代码。

首先提供一些Firebase的测试数据供参考:

{
  "testModels": {
    "1": {
      "name": "Model one"
    },
    "2": {
      "name": "The second model"
    },
    "3": {
      "name": "Third is the charm"
    }
  }
}

因此它的模型 app/models/test-model.js 只需要其中的名称。

这是我的 belongsTo 类代理 class,我把我的放在 app/utils/proxy-class.js 下,但它应该是一个 Mixin:

import Ember from 'ember';

export default Ember.Object.extend({
  remote: null, // reference to the remote DS.Model

  store: null, // reference to the actual store
  storeModel: null, // name of the model in the store

  _watchRemote: function() {
    var self = this;
    if ( typeof self.get('remote') === 'object' ) {
      // do nothing, already an object
      if ( ! Ember.isPresent( self.get('store') ) ) {
        // but set the store from the model
        self.set( 'store', self.get('remote.store') );
      }
    } else if ( typeof self.get('remote') === 'string' ||
                typeof self.get('remote') === 'number' ) {
      // it's an id, so fetch the model
      self._fetchModel( self.get('remote') );
    }
  }.observes('remote').on('init'), // on change, and during object init

  _fetchModel: function( id ) {
    var self = this;
    self.store.find( self.get('storeModel'), id ).then(
      function( model ) {
        self.set( 'remote', model );
      }, function ( err ) {
        console.error( "couldn't read from the store:", err );
      });
  },
});

我创建了这个控制器,并使用浏览器控制台即时更改模型以测试模型更改是否被提取:

import Ember from 'ember';
import proxyClass from '../utils/proxy-class';

export default Ember.Controller.extend({
  model: {
    remoteFromId: null,
    remoteFromModel: null,
  },

  init: function() {
    var self = this;

    self.set( 'model.remoteFromId',
      proxyClass.create({
        remote: 1,
        store: self.get('store'),
        storeModel: 'test-model',
      })
    );

    self.get('store').find( 'test-model', 2 )
      .then( function( model ) {
        self.set( 'model.remoteFromModel',
          proxyClass.create({
            remote: model,
            storeModel: 'test-model',
            // no store provided here: set from the model
          })
        );
      });

  }
});

控制器模板:

<p>remoteFromId: {{model.remoteFromId.remote.id}}
  {{model.remoteFromId.remote.name}}</p>
<p>remoteFromModel: {{model.remoteFromModel.remote.id}}
  {{model.remoteFromModel.remote.name}}</p>