Not logged in (Log in or Sign up)

unwwwritten

A bunch of pages

In my last post, I enumerated the "requirements" for this site/blog. While there is still a lot to do, a number of items have already been completed.

I'm going to take the time, over the next several posts, to actually talk about most (if not all) of these features and try to find something interesting in the implementation.

Some of these may be old news for you Rails "veterans", but hopefully I'm touching on some new ground too.

First on my list was...

  • a fully integrated site with multiple pages (including a home page, a project portfolio, an about page and, of course, the blog)

So, how to tie it all together? I don't want a bunch of completely static pages, and I don't want HomeController, ProjectsController, BlogController and AboutController... yech...

So, I used a method inspired by a post on Josh Susser's blog.

I was going to need a "home" page, a "projects" page and an "about" page, in addition to my blog. This could be handled nicely by two controllers, a BlogController and a PagesController.

Now, don't get distracted by my initial proposal of a single BlogController rather than a PostsController and a CommentsController (or any other architecture)... I'm simply walking you through my initial thought process.

The controller implementation for this could be quite simple...

class PagesController < ApplicationController
  def show
    render :action => params[:page]
  end
end

Then, each static page could be implemented with an appropriate view (taking advantage of shared layouts, erb, etc.), and a simple pair of routes could take care of this case...

map.root :controller => 'pages', :action => 'show', :page => 'index'
map.page ':page', :controller => 'pages', :action => 'show'

Easy, right? Well, just to complicate things. I decided that I wanted to be able to have pages for each of my individual projects too. For example, in addition to 'home', 'projects' and 'about' I wanted to be able to have 'projects/ramjet' and 'projects/heisenberg_compensator' pages.

In order to do this, and not have to add a bunch of specific routes, I took advantage of Route globbing and added the following single route in place of the preceding two...

map.page '*path', :controller => 'pages', :action => 'show'

This means that I can change the PagesController#show method to...

def show
  render :action => params[:path].join('/')
end

Now, what happens if someone hits my site with a path for a page that doesn't exist? Unless we do something to handle it better, we'll get get an ugly "Template is missing" page with the details of what template is missing (for example, "Missing template pages/ack/thpt.html.erb in view path /Users/brentf/Sites/unwwwired/app/views").

The way I've handled it is to rescue the ActionView::MissingTemplate exception in my PagesController as follows...

rescue_from ActionView::MissingTemplate do
  render :file => "#{RAILS_ROOT}/public/404.html", :status => 404
end

Now, since we only have one method (show) in the PagesController, it would have been just as easy to simply add a rescue right in the show method itself. However, this lets us extend the functionality in our PagesController and the exception will already be handled for us. In the future it might be an idea to refactor this a bit and move the handler to the ApplicationController instead (so that all of our controllers benefit from the handler). It also may prove handy to only rescue the error in the production environment (so that we still get the details of the missing template during development).

There's lots more to look at, like integrating the pages into a navigation menu, but I think that's enough for now.

Cheers.

blog comments powered by Disqus