Source: seolp.com

By default, Rails uses ID’s in URLs. For example, let’s say we have a list of categories stored in the categories table of the database. The “Super Cool” category is stored with categories#id = 5. To view that category our URL will look like:

http://yourAwesomeDomain.com/category/5

That works great, but it’s not very user friendly. It’s also not very good for SEO purposes. A better URL would use a human-readable and search-engine-decipherable slug instead of an ID. For example:

http://yourAwesomeDomain.com/category/super-cool

How do we get that? Easy!

First, add a column named “slug” to the categories table:

# dbmigrate20120402020611_create_categories.rb

class CreateCategories < ActiveRecord::Migration
  def change
    create_table :categories do |t|
      t.string :name
      t.string :slug
      t.timestamps
    end
  end
end

Next, add these lines to your category model:

# appmodelscategory.rb

class Category < ActiveRecord::Base
  before_create :generate_slug
  attr_protected :slug

  def generate_slug
    self.slug = name.parameterize
  end

  def to_param
    slug
  end

end

Bam! You are done. Your rails helpers and other logic will now automagically use slugs instead ID’s. For example:

@my_new_cat =  Category.create(:name => 'Super Cool')
=>  #<Category id: 3, name: "Super Cool", slug: "super-cool", created_at: "2012-04-02 18:43:08", updated_at: "2012-04-02 18:43:08">

category_path(@my_new_cat)
=> /category/super-cool

link_to(@my_new_cat.name, @my_new_cat)
=> <a href="/category/super-cool">Super Cool</a>

And in your controller, you can find the category by searching with the slug:

# appcontrollerscategory_controller.rb

class CategoryController < ApplicationController
  def show
    @category = Category.find_by_slug(params[:id])
  end
end

Pretty cool, huh?