How I created pretty URLs on my Ember blog with Rails

Thursday, November 6th 2014

This was one of the first challenges I faced when I started building my blog in Ember. Looking back at it my solution was pretty simple but the process getting the solution wasn't. My blog is an Ember front end and Rails back end. So we're going to be talking a lot about both here. Thankfully Ember data made things much easier for me!

Rails Code

First we need to set up the rails app to store the post slug on the posts table. This is important! If we don't store the slug we won't be able to look it up later in the ember app. My migration looks a little something like this:

create_table :posts do |t|
  t.string :title
  t.string :post_slug
  t.text :excerpt
  t.text :body

  t.timestamps
end

We store the slug as a string. You can name it whatever you would like, I chose to call it a "post_slug". Now that the DB is ready we need to set up our show action in the controller. In my app/controllers/api/posts_controller.rb the show action code looks like this:

def show  
  render json: Posts.find_by_post_slug(params[:id]) || Posts.find(params[:id])
end

We either find the post by the slug (which comes through in the request params) or we find by ID. I made it so we can look up either slug or id and the API returns us the same data. That's really it for the rails side of things.

Ember Code

The ember side of things is what took me the longest to figure out. Looking up a post through its ID is really easy.

return this.store.find("post", params.post_id)

It's a little harder when you want to start passing in a slug to lookup. First lets take a look at how my route is set up:

this.resource("posts", function() {
  ....
  this.route("show", { path: "/:post_slug" });
  ....
});

Simple enough. Ember knows it's going to be looking for something named post_slug in the API. Now lets go to our route

var PostsRoute = Ember.Route.extend({
  model: function(params) {
    return this.store.find("post", params.post_slug).then(function(slug) {
      return slug;
    });
  }
});

The model method has params passed into it and when this route is invoked, it will check the params. Inside of the params we have the slug of the post that was clicked. We have to do some more work to get the proper post to render though.

  • Go find the correct post from the store
  • After the promise is returned we return the post that was found with that slug.

Creating a new post

We need one final part to make sure the slug is set and saved to the database when creating a new post. You can do this two ways. In your rails app you can create the slug (which I don't do) or you can use the ember app to create the slug and send it to the back end. In my posts new controller I take the title and run it through a little regex to create the slug.

post_slug: this.get("post.title").replace(/\W/g,'-').replace(/-{1,}/g,'-').replace(/^-|-$/g,'').toLowerCase(),

I'm not sure which place is the best place to do this. I'm open for suggestions! :) But for now I let ember handle it and it seems to be doing just fine.

Conclusion

This was a fun learning experience and I'm still learning! If you have any suggestions please let me know. I write these posts to learn and become a better developer through the power of community!

If you need to reach out to me personally you can do so through Twitter!