Youtilize

Read all about technology, web development and creative entrepreneurship

How to: Generate permalinks in Rails

Simply put, permalinks are great for SEO, but not only that, they make our URLs human readable for easier identification.

For blogs, just like tags and comment systems, they’re a must (or a standard I should say.)

Permalink generation

Case: Say your Post model has a ‘permalink’ field that will contain a string value of your automatically generated permalink.

When you submit a new post, simply do the usual new and save commands in your Controller. For example:

@post = Post.new(params[:post])
if @post.save
  flash[:notice] = "Post '#{@post.title}' saved successfully" 
    # and so on...
end

Now open up your Post model and add the following filter:

before_create :generate_slug

This will make sure that before a new post is saved, generate_slug function will execute automatically.

Below in your Post model, add the actual meat of this action:

protected
  def generate_slug
    self.permalink = title.gsub(/\W+/, ' ').strip.downcase.gsub(/\ +/, '-')      
  end

This simply takes the title attribute and passes it through a few RegEx replacements leaving you with a nice permalink.

For some reason, it took me a while to find this snipped online, so I wanted to make it available for other beginners. (Probably because everyone else just writes their own RegEx!)

Things to improve

» Make sure permalink isn’t already in use (thanks Joel)

» Make sure permalink isn’t too long (thanks Jason)

Other options

This could simply be done with JavaScript as another alternative.

11 Comments

Joel
about 1 year ago

Still need to fix the overflow situation there dimitry ;)

Something to consider should be the existence of a duplicate post. Perhaps add something to your protected method ;)

Dimitry
about 1 year ago

Joel: Good points and something to think about.

› I’ll fix overflow tomorrow hah. Keep forgetting about it.

› As far as duplicate posts, I never even thought of that b/c my blog is so damn small so far. In the future though this may be a problem.

I need to sleep on this (so so late here) and think of a nice sql-effective solution :)

Jason
about 1 year ago

John Gruber wrote about permalink design a little bit in one of his articles,

http://daringfireball.net/2007/03/blank_slate

I think one thing you might want to consider is adding in the option to override the default permalink so that if a title is unusually long, the URL doesn’t have to be as well. As John wrote in his article,

“Long titles can be amusing; long URLs are simply annoying.”

Dimitry
about 1 year ago

Jason: Thanks for sharing that link. In my backend I usually save a post in draft mode (for proof-reading, check if permalink is awkward or too long) then Publish it.

That is a good addition though (max length) and will have to add it.

Nicolas
about 1 year ago

Hi guys,

What do you think of this solution: http://www.notsostupid.com/blog/2006/07/07/urls-on-rails/

Could be a nice alternative.

Richard Crowley
about 1 year ago

This is a nice solution, but I wonder if its overkill. Once you have

@post = Post.new(params[:post])

you should be able to interact with the title to do

@post.title.gsub!!.downcase!!(/\ +/, ’-’)

and everything will be done in place.

Of course, someone brought up the fact that you might want to edit the permalink, which is easy enough to allow through Javascript. First you’d have to track whether the permalink had been changed. If it had not, the onchange event for the title should update the permalink. Then you can just save it along with your post the first time.

Edit: a bug in your comment text processing caused the !! to be removed in the code – doubling them up fixed it.

Dimitry
about 1 year ago

I think the implementation could be any way you find it convenient (and efficient). The thing I couldn’t find is the actual RegEx (yet it looks simple enough).

The more I think about it, the more I like the Javascript solution to generating permalinks.

Richard Crowley
about 1 year ago

No it didn’t, and Textile killed part of the code. Let’s try again:

@post = Post.new(params[:post])
@post.title.gsub!(/\W+/, ' ').strip!.downcase!.gsub!(/\ +/, '-')
if @post.save
    #...
end
Adam D
about 1 year ago

Nice writeup Dimitry, what happens if someone edits the title of a post, should it re-generate the slug-url? Or does that defeat the purpose?

Currently I have an id value included in the url, and the slug value as well, and always just find by the id.. so the slug value can be modified without breaking the user-experience..

Nice site too, is it RoR?

Word Up – Releod (TR42)

Dimitry
about 1 year ago

Adam: On edit, I simply add another textarea with the slug, kinda how WordPress does it.

That’s interesting about using post id along with the slug. In my case, I save posts in draft and edit them pretty good (title, body, etc.) so by the time I publish it, the title will most likely not change.

But that’s just my personal system (and yup, site’s in RoR)

Adam D
about 1 year ago

Nice work Dimitry, the site looks ace!

Where are you hosting it?

-

For me, I have the slug generated anytime the entry is created,saved,etc. Keep the users updating the website away from that type of thing.. but I guess for your own site you can trust yourself, haha.

Leave your thoughts

Name
Email
  – kept private
Website
  – optional
Human check
  – type in "button"