10

In the Ember docs I found that find() has support for finding by id:

this.store.find('post', 1); // => GET /posts/1

And also by passing arbitrary parameters:

this.store.find('post', { name: "Peter" }); // => GET to /posts?name='Peter'

But in my case I must find by id, and pass an additional parameter to request all fields to be included in the response (some are omitted by default), like so:

this.store.find('post', 1); // => GET /posts/1?include=all

I tried to do it this way:

this.get('store').find('post', params.post_id, { include : 'all' });

But my params were ignored.

This seems a fairly basic use case so I must be missing something...

How can I accomplish this?

Edy Bourne
  • 5,679
  • 13
  • 53
  • 101
  • Do you have a custom adapter? If so, can you paste it? – Matthew Blancarte Jul 14 '14 at 21:53
  • Here is a most-excellent explanation of what to do when "Oh noes, my REST API and Ember-Data hate eachother.", courtesy of @kingpin2k http://stackoverflow.com/questions/17938294/how-do-you-create-a-custom-adapter-for-ember-js – Matthew Blancarte Jul 14 '14 at 22:01
  • 1
    I have looked into Ember's implementation and to implement this I would have to override 3 or 4 methods in the Store, plus the ones in the adapter so given parameters are passed along to it. It's not terrible, but I'd like to avoid this kind of major overriding due to the fact Ember changes quite a bit over time and I'd have to be checking each time I upgrade for compatibility issues, and I'd also possibly miss on improvements they release. I'm thinking to make a pull-request for this, not sure if it'd be accepted but I kinda get the feeling unfortunately it would not. – Edy Bourne Jul 15 '14 at 03:16
  • Support looks to be on the way.... https://github.com/emberjs/data/pull/3976 – Keith Broughton Feb 14 '16 at 19:56
  • @KeithBroughton the pull request doesn't solve the problem described by the original question (passing arbitrary parameters to a `GET /posts/:id` request) – krukid Aug 08 '16 at 10:30

6 Answers6

3

You may have found a workaround the problem by now, but the way to go is to use the adapterOptions on the options argument.

So, let's go:

  1. Where you fetch the model (i.e. a route), setup the custom argument you want. In your case, the include. It goes like this:

    //file app/routes/post/edit.js
    
    import Ember from 'ember';
    
    export default Ember.Route.extend({
      model: function(params) {
        return this.store.findRecord('post', params.post_id, {
          adapterOptions: { include: 'all' }
        });
      }
    });
    
  2. Read this value inside the model's adapter to customize the ajax request:

    //file app/adapters/post.js
    
    export default JSONAPIAdapter.extend({
      findRecord: function(store, type, id, snapshot) {
        if (Em.get(snapshot, 'include')) {
          let url = this.buildURL(type.modelName, id, snapshot, 'findRecord');
          let query = this.buildQuery(snapshot);
          return this.ajax(url, 'GET', { data: query });
        } else {
          this._super(...arguments);
        }
    });
    

UPDATE 1:

On the ember-data newer versions (>= 2.4.0) you can do it out of the box, by calling store.findRecord('post', {include: 'all'});

2

PhStoned's code works but would cause errors if adapterOptions is blank. Here is an improved version.

import Ember from 'ember';
import applicationAdapter from './application';

export default applicationAdapter.extend({
  findRecord: function(store, type, id, snapshot) {
    if (snapshot.adapterOptions)) {
      let url = this.buildURL(type.modelName, id, snapshot, 'findRecord');
      let query = {
        include: Ember.get(snapshot.adapterOptions, 'include')
      };
      return this.ajax(url, 'GET', { data: query });
    } else {
      return this._super(...arguments);
    }
  }
});
Ben Zhang
  • 1,281
  • 11
  • 14
1

You can use queryRecord instead of find if you want to pass additional params to backend.

this.store.queryRecord('post', { id: params.post_id, include: 'all' }).then(function(data) {
  // do something with `data`
});
Navaneeth Pk
  • 602
  • 7
  • 14
  • 5
    unfortunately, this builds a `/posts?id=X&include=all` URL instead of `/posts/X?include=all` as OP requested, and usually RESTful APIs will only support the latter – krukid Aug 08 '16 at 10:15
1

Rodrigo Marroquim answer didn't work for me. So I've come to the following solution
Ember v2.6.0

import Ember from 'ember';
import applicationAdapter from './application';

export default applicationAdapter.extend({
  findRecord: function(store, type, id, snapshot) {
    if (Ember.get(snapshot.adapterOptions, 'include')) {
      let url = this.buildURL(type.modelName, id, snapshot, 'findRecord');
      let query = {
        include: Ember.get(snapshot.adapterOptions, 'include')
      };
      return this.ajax(url, 'GET', { data: query });
    } else {
      this._super(...arguments);
    }
  }
});

usage:

this.get('store').findRecord('modelName', id, {
          adapterOptions: { include: 'all' }
});
zhisme
  • 2,368
  • 2
  • 19
  • 28
0

My suggestion would be to try using the query function rather than the find function. This will allow you to query an unlimited number of filters.

var myStore = this.get('store');
myStore.query('post', { 
    _id: params.post_id,
    include : 'all'
 }).then(function(peters) {
      // Do something with `peters`
});
Russ
  • 81
  • 1
  • 6
  • 2
    unfortunately, this builds a `/posts?id=X&include=all` URL instead of `/posts/X?include=all` as OP requested, and usually RESTful APIs will only support the latter – krukid Aug 08 '16 at 10:23
0

May helpful to use ajax with adapter implementation here:

const { getOwner } = Ember;
let adapter = getOwner(this).lookup('adapter:application');
adapter.ajax(
  adapter.buildURL(`posts/${id}`), 'GET', { data: { include: 'all' } }
);

#> /posts/1?include=all

This ajax solution even better:

const { inject: { service } } = Ember;

export default Ember.Route.extend({
  ajax: service(),

  async model(params) {
    let id = params.id;

    return await this.get('ajax')
      .request(`/posts/${id}`, {
        data: { include: 'all' }
      }).then(({ post }) => {
        if (post) {
          return this.store.push(this.store.normalize('post', post));
        }
      });
  }
});
Alex Strizhak
  • 910
  • 1
  • 12
  • 22