Breadcrumbs & tRails
One of the things I love the most about working in Ruby is that I find myself spending more time thinking about a problem and less time actually writing code. Case in point: constructing dynamic breadcrumb trails for the RoR-based webapp we're working on here in the lab.
An obvious (and incredibly slick) way to build breadcrumbs would be to use acts_as_tree as described here. This doesn't really work in our situation though, as the nodes at different levels of our hierarchy aren't going to be the same model object, and each has a different controller to operate on it. So we need a little more versatility...
For the purposes of this discussion let's say that we have a Major controller, a Minor that lives beneath that, and a SubMinor which is the leaf node in the hierarchy, each operating on their own type of model. We have a private init method on ApplicationController for setting up instance variables that need to be available to the layout. Individual controllers can override this and construct a breadcrumb trail to display in the layout.
So given this, here's an easy way to build a breadcrumb in the SubMinor controller's init:
def init
super
if (params[:id])
current = SubMinor.find(params[:id])
@breadcrumb = Array.new
@breadcrumb << {:title => current.minor.major.name,
:link => {:controller => 'major',
:action => 'show',
:id => current.minor.major.id}}
@breadcrumb << {:title => current.minor.name,
:link => {:controller => 'minor',
:action => 'show",
:id => current.minor.id}}
@breadcrumb << {:title => current.name}
end
end
Then in the layout we render a partial:
render(:partial => 'shared/breadcrumb')
Where the contents of that template are:
<% if !@breadcrumb.nil? %>
<% @breadcrumb.each do |item| %>
<%=link_to(item[:title], item[:link]) %>
<% if !item[:link].nil? %>»<% end -%>
<% end -%>
<% end -%>
So we stuff each (title, link) pair to be represented in the trail into the @breadcrumb instance variable, and then the breadcrumb partial called from the layout just renders out whatever it finds there. If it finds an item without a :link attribute, it assumes it's reached the final step in the trail (our current location). Works great.