36

I've been trying to make my Rails create URLs to show records by using their title instead of their ID in URL such as:

/posts/a-post-about-rockets

Following a tutorial online I did the following:


Because the ID is no longer in the URL, we have to change the code a bit.

class Post < ActiveRecord::Base
  before_create :create_slug

  def to_param
    slug
  end

  def create_slug
    self.slug = self.title.parameterize
  end
end

When a post is created, the URL friendly version of the title is stored in the database, in the slug column.

We also have to update the finds to find records using the slug column instead of using the ID.

class ProjectsController < ApplicationController
  def show
    @project = Project.find_by_slug!(params[:id])
  end
end

At this point it seems to work except showing a record, because find_by_slug! doesnt exist yet.

I'm an extreme newb - where should I be defining it?

Andrew Hendrie
  • 6,205
  • 4
  • 40
  • 71
Elliot
  • 13,580
  • 29
  • 82
  • 118

3 Answers3

20

This isn't necessarily a direct answer to your question, but have you looked at the Stringex plugin (http://github.com/rsl/stringex)? It's a great way to auto-create slugs for your records.

You can just add something like the following to your model:

class Post < ActiveRecord::Base
  acts_as_url :title
end

and it will auto-create slugs from your title and save it to the slug column.

It's also really smart about the way it creates slugs. For example, a title of "10% off, today only" gets turned into "10-percent-off-today-only".

Pretty slick!

deadwards
  • 1,531
  • 11
  • 18
  • I'm getting method not found error for act_as_url. I added the gem to my Gemfile, ran bundle install, restarted the server... – janosrusiczki Jan 07 '13 at 07:32
  • 1
    Make sure you're spelling it correctly. Your comment says `act_as_url`, but it's supposed to be `acts_as_url`. – deadwards Jan 08 '13 at 17:04
13

find_by_foo is not something that you need to define. ActiveRecord will take of it for you, as long as you have a column named "foo". Adding an exclamation point like you did will cause an exception to be thrown if no record is found, as opposed to returning nil without the exception if you don't use the exclamation point.

As for your specific issue, you added your slug to Post, but you're trying to search on Project.

jdl
  • 17,702
  • 4
  • 51
  • 54
2

Stringex gem is great to generate the slug itself, but I don't agree that saving it on the database is a good idea. You need to remember that if something relevant to the slug changes you need to update your slug column to. E consistent.

In the end, it's duplicated information, no matter in what form. I wrote a post exactly because of this reason.

http://blog.ereslibre.es/?p=343

I hope the post is of some help. I tried to explain everything there.

ereslibre
  • 493
  • 4
  • 3
  • You raise a good point about keeping your slug updated. Fortunately, Stringex has an option that will update the slug if the linked field is updated. :) – deadwards Jul 15 '12 at 17:57
  • 2
    Updating the slug can be devastating for indexed pages on search engines, because the url changes and can't be find anymore. So I think, referring to your blog article, that slugs _must_ be data, and not automatically be updated with the referenced field. Even better would be to keep some kind of history of your slugs, and redirect to the most recent slug/url. – Koen. Nov 03 '12 at 11:26