Nested layouts in Rails
I’m working on a new pet project, and I want to keep my layouts nice and DRY. That means I need to nest my layouts. Unfortunately, googling around for how folks were implementing nested layouts put me on the right path, but nothing felt generic enough. I did get put on the right path, though. This post describes my current solution.
The problem scenario is two-fold:
First, we assume that we’re trying to insert a controller-specific layout layer between the most generic layout and the content from the current action’s template.
Generic Header
– Controller-specific header
—- Action-specific content
– Controller-specific footer
Generic footer
Second, the controller may have some inheritance hierarchy that’s more complicated that just inhering from ApplicationController, and I want to render the most specific layout available. For example, my hierarchy might look like this:
- UsersController (defaults for all user-accessible controllers)
- AccountController
- PuppiesController
- AdminController (defaults for all admin-accessible controllers
- SomeAdminThingController
If I’m rendering an action in PuppiesController, I want to first try to render layouts/_puppies.rhtml. If that’s not available, then I’ll try layouts/_users.rhtml. And if there’s no middle-layer layout available, I just want to render the content.
Here’s the solution:
First, set your default layout in application_controller.rb:
layout 'default'
Ensure you’ve got a matching default.rhtml in app/views/layouts/.
Then, you would place the following method in helpers/application_helper.rb:
module ApplicationHelper
def render_best_inner_layout
layouts = []
c = controller.class
while c != ApplicationController do
layouts << c.controller_name
c = c.superclass
end
while (_layout = layouts.shift)
begin
return render :partial => "/layouts/#{_layout}"
rescue ActionView::MissingTemplate
end
end
return false
end
end
Finally, in your default layout, you call that method where you want to render the nested layout. Notice how if false is returned by the helper method, meaning no mid-tier layout was found, we simply yield.
<%= render_best_inner_layout || yield %>
The limitation is that this doesn’t nest infinitely. E.g., if you have a layout nested layout for ‘users’ and‘puppies’, only puppies will be used, rather than chaining users followed by puppies. This suits my current needs, so I’ll let others improve on it as needed.
WordPress mobile
While blogs and some simple social networking-type sites have become commodity software, far too much of the web still faces low-level development challenges that lead to lots of frustration for both the owners of those web sites and for their users.
About six months ago I did a cursory check of a bunch of blogs thought to be SAS — such as WordPress and Blogger — to see if they were iPhone friendly. They were not. Then, yesterday, I found by chance that my WordPress-powered blog is iPhone friendly. My blog being iPhone-friendly is quite a nice surprise, because I’ve been thinking a lot lately about how web site creation is still far too low-level. Years ago I had a MovableType blog that I administered on my own, on a physical server that I owned. While I wanted to be blogging, sometimes I felt like what I was really doing was administering and customizing the blogging software, and not doing enough actual blogging. For non-technies, administration and customization tasks would have been insurmountable barriers to actually having a blog. And even as a techie, when I powered down the server, the blog disappeared forever.
This blog is different. I don’t do anything, and over time, its interface evolves with the changing web. In addition to being iPhone-friendly, WordPress also supports Google gears. The site I started for the Enterprise Rails online community is also SAS, and is powered by Ning. I don’t have to worry about either site, and they just run, letting me concentrate on the content in the sites and not their low-level implementation.
Expect to hear more from me on this topic soon.

blog.chak.org is iPhone friendly
ScoreCard
Pivotal Labs is the creator of Pivotal Tracker, a fantastic task management tool that I use every day. I visited their office in NYC on Thursday to share a project idea with them, which hopefully they’ll build into their tracker software. The idea is called ScoreCard. It takes some ideas from Pivotal’s agile/scrum focus, and some from GTD (Getting Things Done). ScoreCard provides high-level view of all your tasks, organized by project.
These days, people work on so many projects at once — both at work and in their personal lives — that managing everything can become daunting. I counted the tasks in my personal “ToDo” list in Pivotal and found that I had over 150 tasks ahead of me on about a dozen small projects. I don’t need to see all of these tasks at once, because there’s no way I can work on everything at once. What I do want to know is “What are all the projects I’m working on” and “What can I work on now?” I’d also like to know, at a glance, how my projects are doing. Are they getting the attention they need or am I falling behind? Scorecard shows you this information across all your projects in one screen, and hides everything else from view to let you concentrate on what’s most important.
The image below shows the overview screen of all the projects.

ScoreCard project list
Here’s a zoom in on a single project, with an explanation of each part of the interface:

One ScoreCard Project
Like Tracker, ScoreCard gives you info on project velocity via the color of each project summary. It also adds trending (the flag) and a measure of project staleness (the time since last action). For the GTD’er in you, ScoreCard shows you two items from the project’s task list. It shows you the next action you need to focus on (with Tracker-style workflow steps: start, finish). It also shows you the last action you just completed. The tracker notion of “Accept” is assumed (this item will disappear when you complete the next action), but there’s a button to reject the action if you need to for some reason.
So yes, keeping my fingers crossed that the great folks at Pivotal will grant me this wish. If not, maybe someone else will build it for me — any takers? This tool can certainly be built on top of tracker’s web-service API.
hash_extension updated for Rails 2.0.x
Thanks to Wayne E. Seguin for pointing out that extract_options_from_args is gone in Rails 2.0.x. hash_extension 0.0.3 now works in 1.x and 2.0.x. To upgrade:
sudo gem update hash_extension
To install for the first time:
sudo gem install hash_extension
For more info, check out the docs.
Speeding up ActiveRecord with Hashes, Take 2
A few weeks ago, I posted about the release of my gem, hash_extension, which makes Ruby hashes act a little more like plain old objects. That’s a good thing, because ActiveRecord requests that return hashes instead of full-blown ActiveRecord objects are about 50% faster. 50% is not a performance tweak — it’s basically the best thing that’s ever happened to ActiveRecord.
In version 0.0.1, the only way to get back hashes from ActiveRecord for use with hash_extension was to use select_all:
Foo.connection.select_all("select * from foo")
In the docs for hash_extension I put out a call for someone to extend ActiveRecord itself to return hashes from more natural, ActiveRecord-esque methods. Elliot Laster answered that call, and now, in version 0.0.2, find_as_hashes and find_by_sql_as_hashes are now available:
Foo.find_as_hashes(:all)
Foo.find_as_hashes(:first)
Foo.find_as_hashes(:all, :conditions => "bar = 'baz'")
Foo.find_by_sql_as_hashes("complex sql goes here")
To learn more about the gem and to download, go here.

1 comment