Resource Everything

Rails has some really cool features, and routes.rb is awesome once you get over your initial fear. I was digging through Railscasts to find a way to tidy up all those actions which don’t really fit into a resource. You know the ones. The landing page, the ‘About Us’ page. Ryan Bates has an excellent screencast on tidying up your routes for these actions, and I thought that it would be cool to take it a step further so we can have static pages which are still editable and still (mostly) resourceful.

There are some caveats which go along with this: you can’t create new pages without editing your routes.rb file; the pages all have to fit within a certain framework (mine simply had two columns – ‘page’ and ‘body’); and the names of the page and those specified in your routes.rb file have to match. I still think it’s worth doing, however, since you can set up a handful of pages which the client can edit without you having to update the html constantly.

Step 1: Set up your routes.rb file

I initially set up a resource called ‘Information’, and Rails is kind enough to know that ‘informations’ is just plain dumb, so gives us a singular table name instead.

In your routes.rb file, you need to set up a custom method along these lines. I modified this slightly, calling it ‘general_actions’ and left off the controller name from the url. So my method call looked like:

def map.general_actions(actions)
  actions.each do |action|
    self.send(action, "/#{action}", :controller => 'information', :action => action)

with the following actions defined:

map.general_actions %w[ biography history ]

This gives us the urls ‘/history’ and ‘/biography’.

Step 2: The model

The migration for this model was set up as

  t.string :page
  t.text :body

There needs to be a corresponding entry for each page listed in the array passed to general_actions, so we create two (I just did it in the console); just the name of the page corresponding to the action, and some dummy text.

Next we change the to_param call in information.rb, so that it will return the page rather than the id of the object. We can achieve this with the following lines:

  validates_presence_of :page
  validates_uniqueness_of :page

  def to_param

If you’ve never played around with the to_param method before, there is one thing to take heed of: if you don’t include the primary key at the beginning (default is integer in Rails), the standard find method will break. In this instance, whenever I want to find the model, it needs to call find_by_page instead.

Step 3: The Controller

Last but not least, we work the magic to get it to generate a nice url for each page, rather than the standard resource url of /:controller/:id. We do this by calling a filter before the show action. (I include the definition of @information in the show method itself just to be sure. Likely you would also have some form of administration filter on all the other actions so they are inaccessible to the general public.)

  before_filter :intercept_page, :only => [:show]
  def show
    @information = Information.find_by_page(params[:page])

  def intercept_page
    @information = Information.find_by_page(params[:action])
    render :action => 'show'

So now we have the urls /history and /biography available via the history_path and biography_path helpers respectively, with the ability to add new pages simply by including the name in the array of general actions in the routes.rb file and a valid database entry. What I particularly like about this is that all the list and editing functionality is still resourceful – it is only the public url which is ever modified.

Addendum: The View

There really isn’t much to the view in this case. You’ll need to set up your form and edit pages as per other resources; the show page in my case was simply:

<h2><%= -%></h2>
<%= textilize(@information.body) %>

(I’m not a fan of storing html in the database; I much prefer to use Textile and RedCloth to handle custom input.)


I find this a nice way around the problem of editing static pages, and with the judicious use of caches_page and sweepers monitoring any updates, you can still cache them as static pages.


~ by MattR on November 7, 2008.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: