Search code examples
ember.jsember-dataember-cli

Ember-Cli: prepend a findAll() query with a prefix


In one of my routes I need to findAll() of user's Items, but instead of making the standard /items request it has to go to /my/items.

My current solution involves:

// routes/my/item.js
export default Ember.Route.extend({
    model() {
        this.store.unloadAll('item');
        return Ember.$.getJSON('/my/items').then((payload) => {
          this.store.pushPayload(payload);
          return this.store.peekAll('item');
        });
    }
});

But unfortunately it's not ideal since it requires to unloadAll() items before making the request as to ensure that the model only returns freshly fetched records while unloading any cached.

A better solution will probably involve creating a custom adapter specifically for this route and overwriting either the findAll() method or urlForFindAll(), but I'm not sure how to properly create and import such custom adapter.

Just for testing I overwrote the default Item adapter and returned findAll('item') in the route's model, and everything worked, the request was prefixed with /my/:

// adapters/item.js
findAll: function(store, type, sinceToken, snapshotRecordArray) {
  var query, url;
  if (sinceToken) { query = { since: sinceToken }; }

  // prefix url with `my` str
  url = `my${this.buildURL(type.modelName, null, null, 'findAll')}`;
  return this.ajax(url, 'GET', { data: query });
},

// routes/my/item.js
export default Ember.Route.extend({
  model() {
    return this.store.findAll('item');
  }
});

..but that obviously overwrites all findAll() queries for this model, wherein I need to make a custom query only in this route.


Solution

  • This can be solved by using adapterOptions to pass options to the item's adapter using findAll:

    1) In the route use adapterOption to pass prefix to the adapter:

    return this.store.findAll('item', { adapterOptions: { prefix: 'my' } });
    

    2) In ember-cli overwrite item's default adapter with ember g adapter item.

    3) In the adapter overwrite the default findAll to prefix url if such option is passed:

    // /app/adapters/item.js
    import ApplicationAdapter from './application';
    
    export default ApplicationAdapter.extend({
      findAll: function(store, type, sinceToken, snapshotRecordArray) {
        var query, url;
        if (sinceToken) { query = { since: sinceToken }; }
    
        let prefix = Ember.get(snapshotRecordArray, 'adapterOptions.prefix');
        url = `${prefix || ''}${this.buildURL(type.modelName, null, null, 'findAll')}`;
    
        return this.ajax(url, 'GET', { data: query });
      },
    });
    

    4) Success, this.store.findAll('item', { adapterOptions: { prefix: 'my' } }); will now make a my/items instead of items!