Creating Pretty URLs From Multiple Attributes With friendly_id
a brief tutorial on how to make pretty urls for your Rails models using multiple attributes rather than one
6 comments 3 linksI wrote an article back in August about the wonderful friendly_id plugin and the utilities thereof. Long story short it became one of the more popular articles on the site (probably the most, really, as we didn't start tracking pageviews on the server side until early September) and I thought it might be useful to discuss how to extend its functionality a little bit.
some history
So friendly_id, for those of you too lazy to click on any of the above links, is a really nifty pretty-url plugin for Rails that provides you with a full library of methods for taking any given attribute on a Rails model and filtering that attribute to become the primary resource locator in lieu of the rails default, the record's id.
For example, if you wanted your article title URIs to use the article title rather than id, you'd do something like this:
#!/app/models/article.rb has_friendly_id :title
Then, magically, and without explanation beyond the fact that the gods are benevolent and sometimes when we wish for things to happen they simply do, any time you find a record in the your Articles controller with Article.find(params[:id]) friendly_id will automatically interpret the url string and find the corresponding Article's id.
Take a look. In essence it's turning this:
http://www.mydomain.com/articles/33
Into this:
http://www.mydomain.com/articles/this-is-much-more-explanatory-and-seo-friendly
So that's the really basic version of what it does. And after I posted that initial article, a gentleman named Shaun posed a very interesting question, and one for which I didn't immediately have an answer.
I knew that if you wanted to customize the slugged field you could do so by passing that attribute into a block at the end of the has_friendly_id method call, like this:
#!/app/models/article.rb has_friendly_id :title do |slug| slug.upcase! + "-my-pet-dromedary-is-ill" end
Now, for whatever ungodly reason, your slugs will appear in all uppercase letters and indicate that your pet dromedary is ill. Cool, kind of.
But what Shaun wanted to do was to come up with a solution that integrated his created_at date into that block. Which I thought would be easy enough, something like:
#!/app/models/article.rb has_friendly_id :title do |slug| slug + "-" + created_at.strftime('%Y-%m-%d') end
Needless to say, I'm not very bright, and this didn't work because the created_at call, which was trying to read the created_at method on the Article model, was out of scope, because it was inside a block. Another needless statement would be to say that self.created_at didn't work either because again, I was calling it on a block.
So being the genius that I am, I put my faith in Shaun and let him come up with the solution on his own. And sure enough, he came through:
#!/app/models/article.rb has_friendly_id :title_with_date protected def title_with_date title + "-" + created_at.strftime('%Y-%m-%d') end
Neat, huh? In case you were wondering, the result looked something like this:
http://www.mydomain.com/a-really-seo-friendly-and-still-readable-url-2010-01-01
Cool, huh? Thanks for the help, Shaun. I get the feeling that this'll be useful to people.
update
Shaun strikes again. For anybody who read the article before, I referenced the use of Stringex to convert the title to a proper url format, but scholar that he is, Shaun recognized that it doesn't matter which attribute/value you pass into has_friendly_id, it will be converted to a proper format on the backend. Thanks again, Shaun. You're the man.
3 links
6 comments
Glad you like it, Verdi -- I aims to please.
Hey Mike,
Great write up! One comment/question - I don't think you need Stringex in this example, because friendly_id will add the dashes for you (make the slug), right?
It's just a matter of adding the dashes yourself with Stringex vs. using friendly_id to add the dashes, yeah?
Shaun
Shaun! You're absolutely right! Good call. I'll post an update right away. Good eye -- and thanks again for the great contribution.
You should register a user account to keep track of your comments. At some point I'm going to be implementing a user karma system, and the comments will boost you up the active users list. Just a thought...
No problem^ and I signed up for an account too. ;)
Btw, does your rss feed work?
Shaun
Thanks for the writeup on friendly_id! I'm glad you find it useful.
post comment
markdown basics
| **bold** __bold__ | [link](http://link.com "link") | * unordered list item |
| *italic* _italic_ | ##h2 heading | 1. ordered list item |
| > blockquote | ####h4 heading | <code>@ruby</code> |
This is great!