Fetching single records


#1

Fetching a collection records in Ember Data is trivial but what is not is a single arbitrary record. There are times when you may not know the ID of the record but require to fetch it (ie. current user). It’s hard to do because Ember Data expects the ID to use as a reference. Why not just direct AJAX request but doing so don’t use some of the niceties that Ember Data provides, such as promised models etc.

Is this a use-case that few find required or is this something that is planned to be addressed later on?


#2

I may not be fully understanding the problem you are describing, but Ember Data does allow you to find records via attributes other than the ID. As the documentation states, that’s assuming that your server is capable of interpreting the hash that is passed.


#3

The issue with loading a single record not based on an ID, is that you need to get back a DS.Model object as a promise. If you get back a record that’s already in the client’s memory you would now have two diffrent objects representing the same record (type and id combination). Take this example:

var user123 = App.User.find(123);
var currentUser = App.findByUrl('/users/current'); //This is an imaginary method, i.e. Ember Data don't support it
notEqual(user123, currentUser, "The user objects can't be the same cause we don't know what the current user is yet");

Now we get this response from the server:

{
  "user": {
    "id": 123,
    "name": "Mufasa"
  }
}

Now currentUser and user123 both have id 123, but they are essentially different objects = very bad. This is why this approach wouldn’t work.

Instead you will want to load a record array of users, listen for it to load, and then take the firstObject from the loaded records. Like this:

var users = App.User.find({is_current: true});
users.one('didLoad', function() {
  App.set('currentUser', users.get('firstObject');
});
//Or load it via AJAX yourself
$.ajax({
  type: 'GET',
  url: '/users/current',
  success: function(payload) {
    var store = DS.get('defaultStore');
    var userReference = store.load(App.User, payload.user);
    App.set('currentUser', store.recordForReference(userReference));
  }
});

#4

This really depends on the use case. Here’s a related issue and a blog post in which I describe one possible solution with promises


#5

@seilund makes an interesting point. In that, I’ve played around with the idea of mixing his approach and proxy objects. The end result is an object that can be used straight away while loading asynchronously. The end result being something like:

var SomeObject = Ember.ObjectProxy.extend({
  init: function() {
    var self = this;
    AnotherObject.find({foo: 'bar'}).then(function(results) {
      self.set('content', results.get('firstObject'));
    });
  }
})

#6

@evilmarty does your code work? Can SomeObject be used as a return value for find function?