views:

110

answers:

3

Let's say I have a Ruby on Rails blogging application with a Post model. By default you would be able to read posts by http//.../post/id. I've added a route

map.connect ':title', :controller => 'posts', :action => 'show'

that will accept http//.../title (titles are unique) and the controller will do a query for the title and display the page. However when I am now calling <%= link_to h(post.title), post %> in a view, Rails still gives me links of the type post/id.

Is it possible to get Rails to automatically create the pretty links for me in this case?

A: 

You can override ActiveRecord's to_param method and make it return the title. By doing so, you don't need to make its own route for it. Just remember to URL encode it.

What might be a better solution is to take a look at what The Ruby Toolbox has to offer when it comes to permalinks. I think using one of these will be better than to fixing it yourself via to_param.

Thorbjørn Hermansen
The to_param does not quite work as it will still put the controller name into the picture. I will however take a look at the permalinks plugins.
Alex
+1  A: 

If you are willing to accept: http:/.../1234-title-text you can just do:

def to_param
  [id, title.parameterize].join("-")
end

AR::Base.find ignores the bit after the id, so it "just works".

To make the /title go away, try naming your route:

map.post ':id', :controller => 'posts', :action => 'show', :conditions => {:id => /[0-9]+-.*/ }

Ensure this route appears after any map.resources :posts call.

cwninja
But this still creates http:/.../post/1234-title-text, i.e. the controller name is still in there :-(
Alex
Oops, missed that, answer updated.
cwninja
A: 

I would use a permalink database column, a route, and I normally skip using link_to in favor of faster html anchor tags.

Setting your route like:

map.connect '/post/:permalink', :controller => 'post', :action => 'show'

then in posts_controller's show:

link = params[:permalink]
@post = Post.find_by_permalink(link)

You link would then be

<a href="/post/<%= post.permalink %>">Link</a>

then in your create method, before save, for generating the permalink

@post = Post.new(params[:post])
@post.permalink = @post.subject.parameterize
if @post.save
  #ect
Chris Allison
Yes, that's what I am already doing. I was hoping Rails would have something like this built-in. One caveat with the above is the hardcoded root URL that will make this app break when run under a subdirectory. ActionController::Base.relative_url_root should be prepended to the URL to be on the safe side here.
Alex