unwwwritten
A bunch of pages
Posted August 8th, 2008 at 12:55 pm PDT by S. Brent Faulkner — View Comments
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