sailsCasts

Learning about sails.js one screencast at a time.

sailsCasts Answers: Ep4 - Creating a More Attractive Url in Sails With slugs...really?

| Comments

Transcript

Howdy and welcome to another thought provoking, informative sailscasts answers. Okay, maybe that’s a bit of a stretch but welcome all the same. I’ve been asked a number of times how to implement a more attractive url system in sails…commonly using slugs.

Let’s take a look at an example. In activityOverlord when you’re on the user profile page, the url is something like this http://localhost:1337/user/show/5220fa7b8764043122000001. The ending part here is a mongoid. And that id is not very human friendly. What would be better is to have something like the person’s username. I’ll be doing a separate episode incorporating attrative urls into activityOverlord, however, in this screencast I’m going to show you how to do it generically for any project.

So I’ll create a new project called slugsville by entering sails new slugsville --linker with the linker flag. Next I’ll change into the slugsville folder and generate a user controller and model using sails generate user. So, let’s take a look at the user model. I’m going to paste in attributes for name, company, email, and phone as well as an attribute called slug.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
module.exports = {

  attributes: {

      name: {
          type: 'string',
          required: true
      },

      slug: {

          type: 'string',
      },

      email: {
          type: 'string',
          email: true,
          required: true,
          unique: true
      },

      company: {
          type: 'string'
      },

      phone: {
          type: 'string'
      }

  }
};

Let’s switch to the user controller. I have a fairly generic create action that creates a user with params I’ll send through the Postman chrome extension and then we’ll return a json object. When the user is created, however, we need to put some logic in that will process the username removing any spaces and lower casing the string before saving the value into the slug model attribute. We’ll do this by adding a beforeCreate() method to our User model.

So going back to the User model, I’ll add the beforeCreate() method first chekcing whether name exists and then assigning the slug attribute the value of name with no spaces and all lowercase. Finally we’ll use the next() method to continue. Let’s see if that worked.

I’ll go into the terminal and start the sails server using sails lift. Next, we’ll go into the browser and using the postman chrome extension, I’ll create a new user with the following attributes. And great both the user and more importantly the slug were created.

So now let’s use this slug as a route parameter. I’ll head over into the `/config/routes.js file located in the config folder where we’ll create two routes.

1
2
3
4
5
6
7
8
9
10
11
12
13
module.exports.routes = {

  'get /:slug': 'UserController.profile',
  'get /user/:slug': 'UserController.profile',

  // By default, your root route (aka home page) points to a view
  // located at `views/home/index.ejs`
  // 
  // (This would also work if you had a file at: `/views/home.ejs`)
  '/': {
    view: 'home/index'
  }
};

Both /:slug and /user/:slug will bind themselves to the profile action of the User controller. In the User controller, I’ll create an action called profile. Next I’ll grab the slug param and assign it to the var slug. I want to let anything we catch with the slug param that has a dot in it like image.png to pass through without hitting our find method. That way we reduce the overhead of searching for a user for params we know are not a name. So if the param has a dot in it, we’ll return next() which will continue to the next piece of middleware (if any).

Next, we’ll try to find a user by the slug attribute passing in the slug variable we obtained form the param. If we don’t find a user, we’ll again return next(). If we do have a user I’m going to pass the entire user object to the view, in this case profile.ejs.

profile.ejs is a simple view template that displays the user name, company, email, and phone. Finally, I’m going to go back to the User controller and add a foo action to make sure that my action blueprint routes still work. If your not familiar with blueprint routes, I’m currently working on episode explaining blueprint routes, the first of which is devoted to action routes. Here I’m just adding the action foo that will return a 200 response.

Okay, let’s see if all of this worked? First, I’m going to create a few other users within postman. Here’s a list of our users. I can still access them via the id using /user/1. But now I can access them by their username either at /username or /user/username. I can also access my foo action.

I think that’s a much better approach. I’ve left a link to this project’s repo here if your interested and I hope that it was helpful and as always thanks for watching.

Comments