Nested Resources with Backbone
The topics I wish to discuss are Backbone and Rails Nested Routes and How do I define nested resources for backbone.js?.
One other thing I wanted to avoid was introducing another plugin in our codebase such as Backbone Relational.
For the sake of this article I will use Articles
, Comments
and Comment Replies
as examples.
Consider the following url structure: /articles/:article_id/comments/:comment_id/comment_replies
This means one article can have several comments, and one article comment can have a several replies.
Consider the following json structure for a comment
:
{
id: 1,
body: 'Sunny day in London!',
url_root: '/articles/1000/comments/1'
}
The url_root
attribute is very important, since it’s the attribute that will make our lives easier in the moment we need to reach the comment_replies
url.
After you prepare your json
response and assuming you have a collection, it all starts with setting a url in the collection, like the following:
<h1>Article Page</h1>
<script type="text/javascript">
// The url param is the one responsible to make
// all the rest work, this is where everything begins
var comments = new App.Collections.Comments({ url: '#{ article_comments_path(@article) }'});
</script>
In your Comments Collection
make sure you set the url
you passed to the collection,
this is accomplished in the initialize
of the collection, by passing the url as an option.
You will need to have that endpoint if you are thinking about CRUD since Backbone uses that path to make a POST
for example.
App.Collections.Comments = Backbone.Collection.extend({
model: App.Models.Comment,
url: function() {
// /articles/:article_id/comments
return this.baseUrl;
},
initialize: function(models, options) {
this.baseUrl = options.url;
}
});
The Comment Model
is the middle resource between the Article
and the Comment Reply
, it’s important that one of the attributes is the url with the article_id
and the comment id
.
App.Models.Comment = Backbone.Model.extend({
url: function() {
// /articles/:article_id/comments/1
return this.get('url_root');
},
initialize: function(options) {
// Here is where we manage to build the nested url
new App.Models.CommentReply({
commentPath: this.url()
});
}
});
Finally the CommentReply Model
receives the url with the necessary attributes in the initialize
and sets it in the url function, allowing it to interact with the server.
App.Models.CommentReply = Backbone.Model.extend({
url: function() {
// /articles/:article_id/comments/:id/comment_replies
return this.urlRoot;
},
initialize: function(options) {
// Here we set this model url,
// which is given by the Comment model through options,
// which will have the dynamic path we need to reply
// to the right comment in a given article.
// /articles/:article_id/comments/1/comment_replies
this.urlRoot = options.commentPath + '/comment_replies';
}
});
I hope this gives you the answer you are looking for and I wish you happy coding.