Recipe:

Linking to slugs


Problem

The default behavior of Ember’s link-to helper and Ember.Route’s model hook make it easy to identify and load records by id. However, you may want to use a human-readable keyword or slug to identify a record in a url in place of an id.

Solution

Ember makes it easy to override the Route’s default model hook. You can define a custom model function to look up records by a slug property instead of by the id.

Changing the link-to to use a slug instead of an id is easy and only requires creating a custom serialize function on the route.

Discussion

Identifying records by slugs is a two step problem. Given a Router mapping that looks like this:

js App.Router.map(function() { this.route('post', { path: '/post/:post_slug' }); });

First the Router needs to know how to look up the record by the slug using the :post_slug param. Then link-to needs to generate an anchor tag with the record’s slug property in place of the :post_slug.

Querying Records by Slug

By default, Ember Data does not provide a way to look up only 1 record by a property (other then the id property). Luckily, it is easy to extend Ember Data’s store object to provide this functionality. The code below adds a findOne method to the store.

js App.ApplicationStore = DS.Store.extend({ findOne: function() { return this.find.apply(this, arguments).then(function(results) { return results.objectAt(0); }); } });

Using findOne we can easily fetch a record by its slug property in the Route’s model hook.

js App.PostRoute = Ember.Route.extend({ model: function(params) { return this.store.findOne('post', { slug: params.post_slug }); } });

Linking To the Slug

The next step is to include a record’s slug in the anchor tag generated by ember’s link-to helper. The normal way to create a link-to would look something like this:

{{#link-to 'post' model}}{{model.slug}}{{/link-to}}

Unfortunately it will generate an anchor tag that includes the Post’s id in the dynamic segment.

html <a href="/post/1">hamster</a>

You can work around this behavior by defining a custom serialize method on the route.

js App.PostRoute = Ember.Route.extend({ serialize: function(model) { return { post_slug: model.get('slug') }; } });

Now using we can use the same link-to code as above and the record’s slug property will be correctly serialize the :post_slug param in the anchor tag’s href.

html <a href="/post/hamster">hamster</a>

Example

Cookbook: Using slugs in links