Rails, Resources and Permalinks

12 April 2007

There has been quite a bit of discussion about creating permalinks with a rails resource. In this article I will show you how to create permalinks for a resource named ‘pages’ without giving up on any of the resource goodness!

Before I start I’ll presume you have a page scaffold_resource setup in your rails application. Make sure you have at least the following fields in your page model:

t.column :title, :string
t.column :permalink, :string
t.column :content, :text

Okay, what you want is the permalink_fu plugin. This plugin greatly simplifies the act of generating a permalink from a title. Install it first:

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

In your Page model you may now add the following line. This line will generate a permalink in the permalink attribute automatically, so you don’t have to show the permalink field in any forms.

has_permalink :title

That’s it for generating the appropriate permalink string in your database.

Rails goodness has already provided you with the basic RESTful routes:

But what you really want, is something like:

Notice that the permalink url is only a GET request and should not be used for editing or updating the page in question.

Since using any other identifier than :id in a resource is madness, I create two new routes that will allow me to access permalinked pages. Not only that, but I do maintain the format option. Basically this means that you get three routes:

Notice that I removed the ’s’ from ‘pages’ here. This is to avoid confusion with the resource ‘pages’. But more on that later.

Now in config/routes.rb add the following two lines:

map.permalink 'page/:permalink', :controller => 'pages', :action => 'permalink'
map.connect 'page/:permalink.:format', :controller => 'pages', :action => 'permalink', :format => nil

The first line adds a named route to an action named ‘permalink’ in your PagesController. This gives you the ability to add peralink links easily:

permalink_url(@page.permalink)

The second link is unnamed, and allows you to specify a format like HTML or XML.

The permalink action looks like this:

# GET /page/perma-link
# GET /page/permal-link.xml
def permalink
  @page = Page.find_by_permalink(params[:permalink])

  respond_to do |format|
    format.html { render :action => 'show' }
    format.xml  { render :xml => @page.to_xml }
  end
end

This special permalink action uses the same ‘show’ view as your resource.

If you want to maintain the ‘pages’ part of the URL, that’s possible. You’ll have to write a condition that makes sure that the :permalink parameter is a string an not an integer (ID). This article does not cover this.

You may now use permalinks for your pages! Congratulations.