Permalinks in Ember

Jekyll has been our favorite tool to generate our static blog website; however, as we've been building all our front-end web apps in Ember, we wanted to move our blog to Ember as well. Recently, we set up our new blog site in Ember. We wanted to keep permalink format for blog URLs as opposed to blog/:blog_id.

What are Permalinks? Permalinks are constructed by creating a template URL where dynamic elements are represented by colon-prefixed keywords. 1

For example, the permalink we want is defined according to the format /:year/:month/:day/:title. Here, I'd like to share how we did to make permalinks in Ember. Let’s get started.

First of all, we need to create a route for a blog, and we want :year, :month, :day and :title parameters in the URL. So the router would be setup as:

Router.map(function() {
  this.route('blog', {path: "/blog/:blog_year/:blog_month/:blog_day/:blog_title"});
});

Our blog site is now an Ember web app that consumes blog data from our server, assuming we have the following data retrieved from the server:

{
    "data": [{
        "type": "blogs",
        "id": "2016/03/30/permalinks-in-ember",
        "attributes": {
            "title": "Permalinks in Ember",
            "created-at": "2016-03-30T08:00:00.000Z",
            "body": "<p>bla bla bla</p>"
        }
    }]
}

Notice above that a blog's id is in permalink format. We assume that the four factors(year, month, day and title) together represent a unique blog id. When a user visits URL(/blog/:blog_year/:blog_month/:blog_day/:blog_title), we get four parameters: blog_year, blog_month, blog_day, blog_title, which are used to construct blog's id. So let's join the parameters to find the blog resource in the route:

// app/blog/route.js
import Ember from 'ember';

const {
  Route
} = Ember;

export default Route.extend({
  model(params) {
    const { blog_year, blog_month, blog_day, blog_slug } = params;
    const currentBlogId = [
      blog_year,
      blog_month,
      blog_day,
      blog_slug
    ].join("/");

    return this.store.findRecord('blog', currentBlogId);
  }
});

And of course, we need a blog model. We could include other attributes such as body, createdAt, author relationship, etc. But that's not the topic here, so let's neglect it. Our blog model would be setup as the following:

import DS from 'ember-data';

const {
  Model,
  attr
} = DS;

export default Model.extend({
  title: attr('string'),
  // ... other attributes
});

This works great when someone visits the URL directly, but we have not yet dealt with when someone clicks a link. Our link-to2 helper takes link text, route name, and blog model as:

{{link-to blog.title 'blog' blog}}

And we want it to generate HTML link as:

<a href='/blog/2016/03/30/permalinks-in-ember'>Permalinks in Ember</a>

However, by default, the serialize function in the route inserts the model's id into the route's dynamic segment (in this case, :blog_id)3, so link-to helper doesn't know values of the parameters: blog_year, blog_month, blog_day, and blog_title. The serialize method in Ember route is:

A hook you can implement to convert the route's model into parameters for the URL 4

We need to override the serialize function in our blog route:

//  app/blog/route.js
import Ember from 'ember';

const {
  Route,
  get
} = Ember;

export default Route.extend({
  serialize(model) {
    const [year, month, day, title] = get(model, 'id').split('/');
    return {
      blog_year: year,
      blog_month: month,
      blog_day: day,
      blog_title: title
    };
  },

  model(params) {
    const { blog_year, blog_month, blog_day, blog_title } = params;
    const currentBlogId = [
      blog_year,
      blog_month,
      blog_day,
      blog_title
    ].join("/");

    return this.store.findRecord('blog', currentBlogId);
  }
});

That's it! Now our permalink works for link-to helper too. It's just that easy to setup permalinks in Ember.

Loading comments...