Mon 30 Jan 2006
I just realized the benefit of something I saw a while ago in a Rails ticket. It is mostly about acts_as_vertical, which is cool and has its uses, but what I’m talking about now is the dynamic StylesheetsController. The way it works in the ticket is that it renders stylesheet based on database values and caches the resulting CSS file.
For CSS this is sort of a novelty until you really become a nazi about the one-place-for-any-given-piece-of-information rule as espoused by the Pragmatic Programmers. When reading about the holy grail of 3-column layout at A List Apart, it struck me that the CSS he’d written, while quite simple, encoded the same pieces of information multiple times - namely widths and padding.
My solution was to reinvent the StylesheetController, which I only later realized I’d seen before. My version looks like this:
class StylesheetsController < ApplicationController
caches_page :content
def content
headers['Content-Type'] = 'text/css'
render :action => params[:name]
end
end
It requires a route that looks like this:
map.connect 'stylesheets/:name', :controller => 'stylesheets', :action => 'content'
Now move your style.css from /public/stylesheets to app/views/stylesheets and rename it style.css.rhtml. Not the prettiest thing ever, but without a new template extension that’s what we have.
Perhaps more important is the realization that this works just as well for javascript files. Now I can use all the Rails helper goodness to construct my static javascript files! How awesome is that? Why hello visual_effect. Hello remote_function.
In case you’re interested, here’s my style.css.rhtml from the article:
< %
right = {:width => 130, :padding => {:horizontal => 10}}
left = {:width => 180, :padding => {:horizontal => 10}}
center = {:padding => {:vertical => 10, :horizontal => 20}}
[right, left, center].each do |column|
column[:full_width] = column[:width] + 2 * (column[:padding][:horizontal] || 0) rescue 0
column[:padding] = {:horizontal => 0, :vertical => 0}.merge(column[:padding])
end
-%>
body {
min-width: < %= 2 * (left[:full_width] + 2 * center[:padding][:horizontal]) + right[:full_width] %>px;
}
#container {
padding-left: < %= left[:full_width] %>px;
padding-right: < %= right[:full_width] + 2 * center[:padding][:horizontal] %>px;
}
#container .column {
position: relative;
float: left;
}
#center {
padding: < %= center[:padding][:vertical] %>px < %= center[:padding][:horizontal] %>px;
width: 100%;
}
#left {
width: < %= left[:width] %>px;
padding: < %= left[:padding][:vertical] %>px < %= left[:padding][:horizontal] %>px;
right: < %= left[:full_width] + 2 * center[:padding][:horizontal] %>px;
margin-left: -100%;
}
#right {
width: < %= right[:width] %>px;
padding: < %= right[:padding][:vertical] %>px < %= right[:padding][:horizontal] %>px;
margin-right: -< %= right[:full_width] + 2 * center[:padding][:horizontal] %>px;
}
#footer {
clear: both;
}
/*** IE Fix ***/
* html #left {
left: < %= right[:full_width] %>px;
}