From Param: How URL-Based Fetching Ought to Be

The addition of RESTful routing and the #to_param method in Rails has undoubtedly improved both the ease and usefulness of URL generation in Rails apps. However, there has come to be a rather insidious tendency to have an auto-generated id as the true reference for a given item. This may make sense for some or even many apps, but by and large records should be referred to by their content, not their ids, in URLs if at all possible. With this goal in mind, I have released from_param, a simple addition to ActiveRecord that makes it dead simple to use better URL finders.

Example

First of all, from_param is meant to simply be the complement of to_param, that is, you should be able to pass Model.from_param(some_parameter) the same way you would pass Model.from_xml(some_xml). Let’s examine how this works in practice:

class User < ActiveRecord::Base   def to_param     "#{id}-#{login.downcase}"   end end  class UsersController < ApplicationController   # GET /users/1-mbleigh   def show     @user = User.from_param(params[:id]) # => <User id=1 login="mbleigh">   end end

Simple enough, and it should look very familiar except that instead of a User.find or User.find_by_id, we have User.from_param. In fact, that’s exactly what this code does: from_param by default will call find_by_id since that is how the default to_param is configured.

Now let’s take something a little more complicated: a blog post title. I definitely don’t want an id in the URL if it’s a permalink, so how can I make an arbitrary parameter found as easily as the id? Simple, just add a param column to your table! Take a look:

class Post < ActiveRecord::Base   def to_param     "#{created_at.strftime("%Y-%m-%d")}-#{title.gsub(" ","-").downcase.gsub(/[^a-z0-9-]/,"")}"   end end  class PostsController < ApplicationController   # GET /posts/2008-04-26-from-param-plugin-released   @post = Post.from_param(params[:id]) # => <Post title="From Param: Plugin Released" created_at="2008-04-26"> end

From Param will auto-magically save the to_param of your model to the specified parameter column (defaults to “param” but you can set it by calling set_param_column) and then automatically know to find by that column if it exists when from_param is called. This way, all you have to do is define a to_param that will be unique to your record and everything else is handled for you!

This plugin is really quite simple, but it establishes a convention that I feel has been missing from Rails for some time: a standard method to call to retrieve a record based on its URL parameter.

Installation

To install the plugin on Edge Rails or Rails 2.1 and greater:

script/plugin install git://github.com/mbleigh/from_param.git

On earlier versions of Rails:

git clone git://github.com/mbleigh/from_param.git vendor/plugins/from_param

Resources

If you have any suggestions for expanding the usefulness of the plugin or run into any problems, please report them on the From Param Lighthouse Project.