Don't Forget to Plant It!

Creating Static Pages W/ Rails ActionViews

Recently, I needed to create some static reporting pages for Skribit.  From a quick search, I got a lot of results that talk about Rails and static pages, but none did exactly what I needed:

  1. To be able to generate pages with different paths from one URL
  2. Pages to persist across Rails deployments

Not seeing any solutions that fit my needs, I set out to come up with my own.  Here is what I ended up with.

First, I needed to add a route for generating/displaying the reports:

1
2
map.reports 'report/:year/:month/:day', :controller => 'report',
:action => 'show', :year => nil, :month => nil, :day => nil

From here, I could just use the standard caches_page :show declaration, but that would only generate the page I wanted if I used /report/2009/05/25 as the URL.  What if I wanted /report to generate the report for the current week?  Well, you can do something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class ReportController < ApplicationController
after_filter :cache_weekly_report, :only => :show
def show
if params[:year]
@year = params[:year]
@month = params[:month]
@day = params[:day]
if File.exist?("#{Rails.root}/public/report/#{@year}/#{@month}/#{@day}.html")
redirect_to reports_path(
:year => @year,
:month => @month,
:day => @day)
else
# render report for a specific day
end
else
today = Date.today
@year = today.year
@month = today.month
@day = today.day
# render report for the current week
end
end
protected
def cache_weekly_report
cache_page(response.body,
"/report/#{@year}/#{@month}/#{@day}.html") if @year
end
end

The magic is in the after_filter method cache_weekly_report.  We basically use the same mechanism Rails page caching uses to save our new report page.  Now, calling /report will generate a static report at /report/2009/05/25, or whatever the current day is.

The last thing to do is to make sure that the reports persist through new server deployments.  That can easily be done with a symlink in your capistrano script:

1
2
3
4
task :symlink_reports do
run "mkdir -p #{shared_path}/report; ln -nfs #{shared_path}/report #{release_path}/public/report"
end
after 'deploy:update_code', 'deploy:symlink_reports'

And that’s it!  What do you think?  I’d love to know if there are any simpler solutions to this.

Comments