Even better looking URLs with permalink_fu

written by Eadz on January 24th, 2007 @ 11:08 AM

Extracted from Mephisto is the handy plugin called permalink_fu. This plugin allows you to use ID-less permalinks, much like that in this blog.

I wrote earlier about how to use to_param for nicer URLs, but these are even better. The plugin automatically turns a field in your model into something that could be a permalink, by stripping out all non english and non alphanumeric letters. It then saves this in a field in your database for future use.

So, onto the HowTo:

First, install the plugin in your rails app.


./script/plugin install http://svn.techno-weenie.net/projects/plugins/permalink_fu/

Now you need to add a field to your database to store the permalink.


./script/generate migration add_permalink_to_article

In the migration we add the field called permalink.


add_column :designers, :permalink, :string
Now for the model code
1
2
3
4
5
6
7
8
9
10
11
class Article < ActiveRecord::Base
        # title is the field name you want to convert to a permalink
        has_permalink :title 
        # you can also specifiy a different permalink field in your database by giving a second paramater
        # has_permalink :title, :my_permalink_field
       
        # we now add the to_param method which Rails's routing uses
        def to_param
              permalink
        end         
end

The permalink field is only populated after the record is validated, so if you have a bunch of records already in your database you can get the permalink field to populate with


Article.find(:all).each(&:save)
If you already have lots of view code written then this is the easy way to get these routes working – in your controller :

@article = Article.find_by_permalink(params[:id])

However that doesn’t seem to pass the smell test using :id rather than :permalink, but will work fine. To use :permalink you will have to change your routing code and your view code :

1
2
3
4
5
6
# in your route file
map.connect 'article/:permalink', :controller => 'article', :action => 'view'
# in your views when linking
link_to "View #{article.title}", {:controller => 'designer', :action => 'view', :permalink => article.permalink}
# then in your controller you can use
@article = Article.find_by_permalink(params[:permalink])

Thats all! I’m always on the lookout for SEO related Rails topics to talk about so drop me a line @ questions at this domain .com.

Like this article? Subscribe to the SEO on Rails feed.

Comments

  • Alex on 06 Feb 10:01

    Hi, Eadz, Great tutorial, thanks for sharing. I have a question of deleting an article. The "article" has a many-to-many relation to the "category": @article = Article.find_by_permalink(params[:id]) if @article @article.destroy end I got the error message like: `destroy_without_habtm_shim_for_categories' Can you please tell me where it goes wrong? Thank you, Alex
  • search_guru on 06 Feb 20:04

    Hello, I found the above plugin useful. But what if you have two articles by the same title. Would it be better to put an id in the permalink or test if the permalink exists then put a suffix. thanks,
  • Eadz - SEO on Rails on 07 Feb 05:55

    Hi! Alex - this seems to be a known rails bug - http://dev.rubyonrails.org/ticket/4386 search_guru - originaly in this article I had a validates_uniqueness_of :permalink, but becasue of the way permalink_fu works - it hooks into the before_validation callback - this uniqueness validation didn't work. But I think the idea would be to enforce unique titles and permalinks in the model ( which requires some hacking to permalink_fu ). Failing that, you could check to see if it exists and then as you suggest ad a suffix like '2'
  • Ben Reubenstein on 29 Mar 02:23

    Great tutorial... Rock over London, Rock on Chicago.
  • Gustavo on 15 Apr 01:10

    Designer is a new controller? Give me one example of URL for this. I need help. Thanks
  • Johannes on 19 Apr 13:15

    wouldn't it be possible to do like this instead of "has_permalink": class Category < ActiveRecord::Base def before_validation self.permalink = PermalinkFu.escape(self.title) end end and then use: validates_uniqueness_of :permalink

Comments are closed

Options:

Size

Colors