5

I am newbie in client side Javascript MVC, first ember.js app.

I follow the instructions here to use ember-rest in creating a post-comments type of nested models.

http://www.cerebris.com/blog/2012/01/26/beginning-ember-js-on-rails-part-2/

I started writing nested resources as follow:

  resources :conversations do
    resources :comments
  end

Now the problem is when I had to write the ember-rest controller:

App.commentsController = Ember.ResourceController.create({ resourceType: App.Comment resourceURL: '/conversations/:id/comments' });

I don't think I can use the :id in the middle; how could I work around that? Does ember-data solves this? It seems spine.js integration will be slightly easier to handle this. Thanks in advance!

Jerry Deng
  • 467
  • 4
  • 15

1 Answers1

6

I've been meaning to answer your comment on my post from yesterday, so I'm glad you asked the question here.

I should start by saying that I wrote ember-rest as a very thin layer over jQuery.ajax. It's not terribly advanced, and there is not even a built-in facility for associations. However, I am considering adding one now that this lib is getting a fair bit of use. As you'll see from the code below, this concept can be handled but should be better abstracted in the lib.

Associations can be handled by creating an instance of a resource controller within each parent resource. Each particular resource controller should manage a particular array of resources, but not necessarily all the resources of a particular type.

In your case, you could extend ResourceController to manage comments for conversations:

  App.ConversationComments = Ember.ResourceController.extend({ 
    resourceType: App.Comment,

    // override _resourceUrl() to base the url on the conversation
    _resourceUrl: function() {
      return this.get("conversation")._resourceUrl() + "/comments";
    }
  });

You could then configure an instance of ConversationComments for each conversation:

  App.Conversation = Ember.Resource.extend({
    resourceUrl:        '/conversations',
    resourceName:       'conversation',
    resourceProperties: ['prop1', 'prop2']

    // init comments
    init: function() {
      this.set("comments", App.ConversationComments.create({ conversation: this }));
    }
  });

Last but not least, you'll need to retrieve the comments for each conversation:

  conversation.get("comments").findAll();

If you have all the comments in json, you could alternatively use loadAll(). Where and when you call loadAll() or findAll() depends on your app's needs. Obviously, you will want to reduce the number of ajax calls for best performance.

Ember-data is a much more ambitious project than ember-rest, and already has support for associations as well as advanced features such as transactions. With that said, it's under very active development with a changing API. If you're patient and willing to dig into the code, I highly recommend trying it out. When the dust settles a bit, I also plan to blog about it.

Dan Gebhardt
  • 3,251
  • 1
  • 18
  • 15
  • Thanks a lot for your detailed response. I am trying to see how much changes I need to do to use ember-data. Still thinking. – Jerry Deng Mar 01 '12 at 19:00
  • I started implementing your approach and it seems that PUT or submit function of the edit.js which calls comment.saveResource() still fail due to PUTing the json to "/comments" path instead of "/conversations/:conversation_id/comments/:id" How would I create the duplicate like you suggested in your blog post for editing? – Jerry Deng Mar 01 '12 at 23:23
  • Nevermind my question, I myself removed the "resources :comments" and only kept the nested resources configuration in routes.rb – Jerry Deng Mar 01 '12 at 23:46
  • Jerry - That works. You also could override _resourceUrl() for App.Comment to return "/conversations/" + this.get("conversation_id") + "/comments/" + this.get("id"); – Dan Gebhardt Mar 01 '12 at 23:56
  • Thanks again, Dan. From App.NewCommentView, how can I create that comment object with conversation_id, I tried a dozen different ways and still doesn't seem to have it. – Jerry Deng Mar 02 '12 at 16:38
  • I created comment with var conversation_id = this.get('parentView').get('conversation').get('id'); var comment = App.Comment.create({conversation_id: conversation_id}); now there's little problem of updating the view to show the one just added. – Jerry Deng Mar 02 '12 at 16:57
  • Seems like the ResourceController.extend can let you override the _resourceURL but don't have the pushObjects method. – Jerry Deng Mar 02 '12 at 17:06
  • You should still be able to push objects into the resource controller after creating them. I may just have to extend the lib and write another example to make this more clear, because this comment thread is getting rather hard to follow. If you want to push your own code to github, I could take a look. – Dan Gebhardt Mar 02 '12 at 17:32
  • Dan, I've got it resolved. Primarily because like you were suggesting that it has to be called after it's created. Some real basic concept that I was forgetting. Thanks for your help. A separate demo would always be helpful. I don't think we need to push the code in github. Thanks again. – Jerry Deng Mar 02 '12 at 18:01