ember.jsember-model

How to Model.fetch(<object>) when the returned data is a single object


I want to make an API call for searching that looks like this:

https://myapi.com/search/<query>/<token>

where query is the search term and token (optional) is an alphanumeric set of characters which identifies the position of my latest batch of results, which is used for infinite scrolling.

This call returns the following JSON response:

{
  "meta": { ... },
  "results" {
    "token": "125fwegg3t32",
    "content": [
      {
        "id": "125125122778",
        "text": "Lorem ipsum...",
        ...
      },
      {
        "id": "125125122778",
        "text": "Dolor sit amet...",
        ...
      },
      ...
    ]
  }
}

content is an array of (embedded) items that I'm displaying as search results. My models look like this:

App.Content = Em.Model.extend({
  id: Em.attr(),
  text: Em.attr(),
  ...
});

App.Results = Em.Model.extend({
  token: Em.attr(),
  content: Em.hasMany('App.Content', {
    key: 'content',
    embedded: true
  })
});

In order to make that API call, I figured I have to do something like this:

App.Results.reopenClass({
  adapter: Em.RESTAdapter.create({
    findQuery: function(klass, records, params) {
      var self = this,
          url = this.buildURL(klass) + '/' + params.query;

      if (params.token) {
        url += '/' + params.token;
      }

      return this.ajax(url).then(function(data) {
        self.didFindQuery(klass, records, params, data);
        return records;
      });
    }
  }),
  url: 'https://myapi.com/search',
});

then somewhere in my routes do this:

App.Results.fetch({query: 'query', token: '12kgkj398512j'}).then(function(data) {
  // do something
  return data;
})

but because the API returns a single object and Em.RESTAdapter.findQuery expects an array, an error occurs when Ember Model tries to materialize the data. So how do I do this properly? I'm using the latest build of Ember Model.

By the way, I'm aware that it would be much more convenient if the API was designed in a way so I can just call App.Content.fetch(<object>), which would return a similar JSON response, but I would then be able to set the collectionKey option to content and my data would be properly materialized.


Solution

  • You simply need to override your models load() method to adjust the payload hash to what Ember.Model wants. There are no serializers in Ember.Model. There is both a class level load for handling collections and an instance level load for loading the JSON specific to a single model. You want to override the instance level load method to wrap the content key value in an array if its not one already.

    I have been using Ember.Mode quite heavily and enhanced it for a number of my use cases and submitted PR's for both fixes and enhancements. Those PRs have been sitting there for a while with no response from the maintainers. I have now moved to Ember.Data which has been 'rebooted' so to speak and having a lot better result with it now.

    I would strongly suggest walking away from Ember.Model as it appears dead with the new pragmatic direction Ember Data has taken and because the project maintainer doesn't appear to have any interest in it anymore.