Current way to handle nested resources?


#1

Hi,

The typical case I’m thinking of is the one that appears on ember documentation of a post with comments. So I’ll describe an example situation situation:

  • Let post and comment be models.
  • A post has many comments.
  • However, the only case in which it makes sense to get a post with its comments is when I’m viewing the post on itself in /posts/:id. I do not want to load all the comments when I’m on /posts as they are not needed.

I found this answer in stackoverflow in which they load the comments from the model by using the parent model.

I decided not to set the hasMany relation on post as I did not want to load all comments all the time. Does this make sense? If so, how would I tell ember to load data from the API/posts/:id/comments and still use the post information in the controller?

Or is there any common strategy to handle nested resources when it is unlikely to use all the information?


Also, I read this proposal because it seemed related: Nested URLs for Ember Data's RestAdapter proposal

Were any of the ideas implemented in the RESTAdapter? which ideas are recommended? Some suggested alternatives seem like hacks to me.


#2

So, here’s what I know about the future: the finalization of JSONAPI and Ember Data (to 1.0) seems like it will solve this problem of using nested REST endpoints.

Right now, I manage to get around this issue by setting the namespace for the adapter (in the desired route), for the model (if that makes any sense). It works and is very stable, but not very Ember

Basically, in the same context that you’re talking about, I have this:

  • PostsRoute
  • PostRoute
  • CommentsRoute

In the PostRoute.model method, I am setting the namespace of the CommentsAdapter to be something like /api/posts/:id. So, if you have a list of model post, navigate to the post route with id of 1, you should get a url that fills like this: /api/posts/1. Therefore, when anything past this point asks for this.store.find('comments'), it should use a url of /api/posts/1/comments and work as expected.

The rest of my app doesn’t make random calls to endpoints, so that being said, my data flow is pretty explicit. My workaround would be a PITA if calls for model data (and nested endpoints) happened all over the place, but it doesn’t.

There is a way in which you can use a URL as a reference in your JSON payloads that will ASYNC in related records. However, I chose to move away from that method, because I couldn’t get the record data to work as expected from the store. It was actually more of a headache and was too magical; being explicit in setting adapters did take a little more work, but was at least understandable just by looking at the code.

So, I hope this helps. I’d sure love to know if anyone is doing something different that I may learn from…


#3

Thanks, interesting approach. I didn’t know you could set dynamic namespaces for adapters. How can you set the namespace for CommentsAdapter using ember-cli in the Route?

I’ve tried something like CommentsAdapter.namespace but I get undefined, I also tried CommentsAdapter["namespace"] and CommentsAdapter.get('namespace') with the same results. I’m extending CommentsAdapter from ApplicationAdapter. I’ve also tried re-opening the class and changing the namespace but had no effect.


#4

Here’s some example code from what would be your CommentsRoute:

...

model: function() {
  var post = this.modelFor('post');
  var adapter = this.container.lookup('adapter:comment');
  
  adapter.set('namespace',`api/posts/${post.id}`);

  return this.store.find('comment');
}

...

#5

Thanks, I used your solution, and it seems to be a nice approach. However, ember-data stacks the comments from every post in the browser ‘caché’ for the comments records. Thus, it seems like all the posts have all the comments. How do you deal with this?

EDIT: I now filter the results to see if they are from the appropriate post, that solved the issue.


#6

I updated to ember-cli 0.2.3 today, and it seems you can no longer set the adapter’s namespace that easily. I’ve tried many forms but couldn’t come up with a way to change the namespace now. Have you updated recently?


#7

Here’s the reason why this won’t work anymore as it is: http://emberjs.com/deprecations/v1.x/#toc_access-to-instances-in-initializers


#8

Yeah, I haven’t figured this out yet.

I’m still using ember-data 14.1.


#9

Got it working:

If you can reference this.store, then you can replace all your existing lookups with this:

this.store.adapterFor('model').set('namespace', '/path/to/url');

Here’s the regex I used for the job:

:%s/this.container.lookup\('adapter:(.+)'\)/this.store.adapterFor('$1')/g

#10

Nice, thanks! And the regex is really useful.