Reputation: 4339
I would like to use ember routes and models to build some "ambitious" web apps.
Here's what I'm trying to do. I have a book and author model. While showing a list of author resources, if the user clicks on an author, display via a nested route all the books by that author. So I'd like to treat the author id (or name) as the dynamic segment to pass to the book model. But there seems to be a limitation whereby dynamic segments must be the primaryKey
of the current model, no other model attributes or models can be used.
Do I need to write a custom de/serializer? If so, an example fiddle applicable to this scenario would be much appreciated.
Here is some example code describing what i'm trying to do, with specific questions appearing in comments.
Authors.hbs template
<div class="span3">
<h4>Books</h4>
<ul class="unstyled">
{{#each model}}
{{#linkTo 'authors.books' this}}<li>
{{name}} <small>{{date dob}}</small> <small> {{origin}}</small>
</li>{{/linkTo}}
{{/each}}
</ul>
</div>
<div class="span8">
{{outlet}}
</div>
initialize.coffee
@resource 'books', ->
@resource 'book', {path: ':cube_id'}
@resource 'authors', ->
@resource 'AUTHOR', {path: ':AUTHOR_id'}
# QUESTION How to make the next line retrieve books-by-author from the book model?
@route 'books', {path: '/books/:author_id'}
AuthorRoute
module.exports = App.AuthorsRoute = Em.Route.extend
model: ->
App.Author.find()
BookRoute
module.exports = App.BooksRoute = Em.Route.extend
model: ->
App.Book.find()
# QUESTION How should the model be extended to allow for lookup by attribute?
# model: (params) ->
# App.Book.find { author: params.book_id }
Author model
module.exports = App.Author = DS.Model.extend
name: DS.attr 'string'
origin: DS.attr 'string'
dob: DS.attr 'date'
Book model
module.exports = App.Book = DS.Model.extend
name: DS.attr 'string'
author: DS.attr # QUESTION How to wire together models here?
#author: DS.belongsTo 'App.Author'
publisher: DS.attr 'string'
published: DS.attr 'date'
Upvotes: 0
Views: 131
Reputation: 9092
Sometime ago I've answered a somewhat similar question (and it's also described in the guides) how to link models with associations such as belongsTo
(when a model record belongs to another model) or hasMany
(when a model record has many records of another model associated to it) and how to use multiple models in the same route.
With associations provided by Ember-Data, you can create properties in your model that are (a) a collection of associated records or (b) a single record that is parent of the record in question. And then in your view layer, simply refer to these properties (collection or otherwise) by the name (see proposed template below).
As for your particular app, you can write your models as proposed below:
module.exports = App.Author = DS.Model.extend
name: DS.attr 'string'
origin: DS.attr 'string'
dob: DS.attr 'date'
books: DS.hasMany 'App.Book'
module.exports = App.Book = DS.Model.extend
name: DS.attr 'string'
author: DS.belongsTo 'App.Author'
publisher: DS.attr 'string'
published: DS.attr 'date'
Note that now both models know about each other. This model declaration will give you a data structure similar to the representation below. So every time you have an instance of Book
, you can use its property author
to access properties defined in the Author
model, such as dob
, name
.. etc
_____________________ ______________________ | Author | | Book | |---------------------| |----------------------| (PK)| + id: int |◄-\ |--►►| + id: int |(PK) | + name: string | \ | | + name: string | | + origin: string | \--Ԑ----| + author: App.Author |(FK) | + dob: date | / | + publisher: string | (FK)| + books: App.Book[] |-----/ | + published: date | |_____________________| |______________________|
Relying on the associations you'll be able to refer to Author.books
in your view layer (when iterating a collection that's a property of your controller or model, use content.books
in your view) to get a collection of books by that author and use it with an {{#each}}
block. As an example, take a look in this fiddle, particularly in the template tags/tag in which I am iterating through a list of posts associated with a given tag. Although the sample is for "blog", the same concept can be used for whatever entity type you're currently working with.
So in your case, even in the "authors.author" route, the template could look like the following:
<h3>Books written by <em>{{name}}</em></h3>
<ul>
{{#each content.books}}
<li>
{{#linkTo books.book this}}
<i class="icon-book"></i>
<!-- consider a helper to display the year or format the date
instead of "publisehd" which will display an ugly date -->
{{this.name}} (this.published)
{{/linkTo}}
</li>
{{else}}
<li>
<div class="alert">
<a class="close" data-dismiss="alert" href="#">×</a>
This author hasn't written any books that we know of.. seriously...
</div>
</li>
{{/each}}
</ul>
Note that the {{#each}}
helper is iterating through the collection, that is, instances of Book
model which are available through the associations in the model declarations.
Upvotes: 0