Testing for Record Equality in Ember Data


#1

Hi,

While using Ember Data, I repeatedly find myself needing to test if two records are the same.

If the records are both resolved, this is no big deal; however, often one or both of the records are actually promises that came from a related model. For example:

//app/models/post.js
export default DS.Model.extend({
  subject: DS.attr('string'),
  user:  DS.belongsTo('user', { async: true }),
});
//app/models/user.js
export default DS.Model.extend({
  name: DS.attr('string'),
  posts: DS.hasMany('post', { async: true }),
});
// Code in a route, controller, or component somewhere
const currentUser = this.get('session.currentUser');
const post        = this.get('model');

if (currentUser === post.get('user')) {
  // This is never executed,
  // because post.get('user') returns a promise,
  // which can't be directly compared to a record
}

My question: is there any robust way to test for record equality that handles promise resolving? I keep finding myself using post.get('user').content to fix this problem anytime I know that the promise is already resolved. Obviously this doesn’t feel right.

TL;DR: Promises make testing for record equality really clunky, at least the way I’m doing it.


#2

I’d also love to hear how other people are dealing with this.


#3

Just to revisit this issue, here is the robust, asynchronous way of testing the two records for equality:

Ember.RSVP.hash({
  currentUser: this.get('session.currentUser'),
  postAuthor:  this.get('model.user'),
}).then((hash) => {
  if (hash.currentUser == hash.postAuthor) {
    // Records are equal
    // Do stuff here
  }
});

By wrapping the two records in Ember.RSVP.hash, we’re making sure that they will be resolved if they are promises. If they are not promises, then Ember.RSVP.hash will pass them straight through to the promise handler.

It’s important to note that this code is not synchronous. Like I said in my earlier post, it might be useful to have a clean way of checking record equality in the case where you know that the promises have already been resolved.

Edit: Typo in my code.


#4

That looks good to me. I like that it lets you use object equality (rather than tagging .id on the end of each object, and pathologically having different classes considered equal) and that it will work if one of the objects starts or stops being a promise later on because of code elsewhere changing. :+1:

Thanks for the update :slight_smile: