RubyNation Conference Sold Out!

As one of the organizers, I’m proud to say that the RubyNation 2008 Conference has sold out. All 125 tickets (at $175 each) were sold in 52 days, which is excellent for any technical conference, let alone the first year of a conference. We were also able to attract a number of great sponsors, as well as companies to provide some truly excellent giveaways. Between the tickets selling out and the sponsors, the conference is solidly in the black, which is also gratifying (since there are some pretty hefty hard costs associated with running a conference).

Portland Trip

Portland TripI just got back from a business trip to Portland, Oregon, where I got to spend four virtually uninterrupted days designing RESTful web services with some excellent developers. Staying in downtown Portland was a treat; the city was gorgeous, the weather was delightfully mild and walking through the city was a lot of fun. I also got to try out a bunch of really nice restaurants at company expense. I even managed to catch a glimpse of the majestic Mount Hood from my hotel room.

RubyNation Tickets Selling Nicely

Tickets for RubyNation 2008, a new regional Ruby conference that I’m helping to organize, are selling briskly. We’re at about the 75% mark, with ticket prices due to increase by $25 on July 16th. By my calculations, we’re already in the black based on ticket sales and sponsorships, which is always a vital milestone. My guess is that RubyNation will be sold out at least a week before the conference.

Creating a Breadcrumb Trail in Rails, Part 1

A common feature of many web sites is what’s known as a breadcrumb trail, or sometimes a rabbit trail. A breadcrumb trail is just a listing, generally on one concise line, of the pages that have been traversed in a hierarchy to get to the current page. Each element of the breadcrumb trail is a link to that previous page, and there’s usually some character or image separating the elements of a rabbit trail.

Antimatter < Tools < Home

I decided to create some code in Ruby that would facilitate the creation of breadcrumb trails for Rails web sites. Listing 1 shows the code that I came up with. My goal, of course, was to make this a generic solution that could easily be reused in numerous web sites. 

In this article, I’ll just focus on presenting the code that generates the breadcrumbs. In a follow-up article, I’ll detail some strategies for packaging up this type of feature to facilitate code reuse.

Listing 1: Helper Code for Breadcrumbs – breadcrumbs_trail.rb

module BreadcrumbsTrail

  # Defines the separator used between breadcrumb elements when
  # the breadcrumbs are traversed from right to left, i.e. - the
  # separator points to left.

  def breadcrumb_separator_left
    "<"
  end

  # Defines the separator used between breadcrumb elements when the
  # breadcrumbs are traversed from left to right, i.e. - the separator
  # points to the right. This is the direction in which most
  # breadcrumbs are oriented.

  def breadcrumb_separator_right
    ">"
  end

  # Returns TRUE if the provided value is an external URL and FALSE if
  # it represents the name of a controller. External URL's can be easily
  # distinguished because they begin with "http://".
 
  def is_external_breadcrumb(val)
    val.start_with?('http://')
  end

  # Returns a string containing the HTML for one breadcrumb link within
  # a breadcrumb trail. The first argument is the title of the link, while
  # the second is an array containing the components necessary to build
  # the destination URL for the link.
  #
  # WARNING: Does not work in controllers because the link_to method
  # is only available to views.

  def build_crumb(title, args)
    str = ""
    if is_external_breadcrumb(args[0])
      str += "<a href='#{args[0]}'>#{title}</a>"
    else
      cmd = "link_to '#{title}', :controller => '#{args[0]}'"
      cmd += ", :action => '#{args[1]}'" unless args.size < 2
      str += "#{eval cmd}"
    end
    str
  end

  # Returns a string containing the HTML necessary to display a breadcrumb
  # trail. The first arg contains an array of elements, where the first
  # element is the name of a breadcrumb, the second is an array containing
  # values for assembling a URL (controller, controller & action, or
  # external URL), and so on in alternating fashion. The final arg is a
  # hash containing options, where the only option currently defined
  # is ":direction". This can have values of either "left" or "right", and
  # governs which way the breadcrumbs will be oriented. The default
  # is "right".
  #
  # An example of the method's usage in a view is:
  #
  # <%= show_breadcrumbs(
  #        ['Home', ['main'],
  #         'Tools', ['tools'],
  #         'Antimatter', ['tools', 'antimatter']], 
  #        :direction => 'left') %>

  def show_breadcrumbs(crumbs, opts = nil)
    direction = 'right'                        # Default direction
    separator = breadcrumb_separator_right     # Default separator
    if opts != nil
      dir = opts[:direction]
      if dir == 'left'
        direction = dir
        separator = breadcrumb_separator_left
      end
    end
 
    str = ""
    if crumbs.size > 0
      str += '<div id="breadcrumbs">'
      if direction == 'right'
        i = 0
        while i < crumbs.size
          args = crumbs[i + 1]
          str += " #{separator} " if i > 0
          str += build_crumb(crumbs[i], args)
          i += 2
        end
      else # Direction equals left
        i = crumbs.size - 2
        while i >= 0
           args = crumbs[i + 1]
           str += " #{separator} " if i < (crumbs.size - 2)
           str += build_crumb(crumbs[i], args)
           i -= 2
        end
      end
      str += '</div>'
    end

    str
  end

end

In Listing 1, the show_breadcrumbs method is the real workhorse, i.e. – the method that users are expected to use to generate their breadcrumbs trail. The code can be included within a helper, such as application_helper.rb. From there, the code would be accessible to all views within a Rails application.

Within a view, the show_breadcrumbs method could be called to generate the HTML for the breadcrumb trail:

       <%= show_breadcrumbs(
          ['Home', ['main'], 
           'Tools', ['tools'],
           'Antimatter', ['tools', 'antimatter']],
          :direction => 'left') %>

The first argument is an array, where each breadcrumb element is represented by a pair of array entries. The first value is the name of the breadcrumb, e.g. – the name of the link. The second is an array containing the data necessary to construct the link, such as [controller, action] or [url].

After the initial array argument, the method accepts options. The only currently supported option is “:direction” which can have values of “left” or “right” to define the direction of flow for the trail.

Paths Not Chosen

Is a breadcrumb trail an element of a view? Or should the generation of a breadcrumb trail be the responsibility of a controller?

There’s no right answer, but I chose to consider it part of a view. I placed the breadcrumb generation code in application_helper.rb, which makes it available to all of the views in a Rails application.

      include BreadcrumbTrail

The code could just as reasonably be included in a controller. Of course, it wouldn’t work as-is because the build_crumb method won’t work in a controller. It uses the link_to helper method, which is only available in views. Still, if the method were rewritten to be independent, it could be used in a controller.

The obvious location to reference the library would be application_controller.rb, which would make the code available to all other controllers.

A controller could generate the HTML for a breadcrumb trail as shown below:

       @trail = show_breadcrumbs(
          ['Home', ['main'],
           'Tools', ['tools'],
           'Antimatter', ['tools', 'antimatter']],
          :direction => 'left')

The @trail variable will be visible to the associated view. The breadcrumb trail could be included within a view as shown below:

       <%= @trail %>

Another design decision that I made was to use an array to represent the elements of the breadcrumb trail, with each element represented by two entries within the array. At first glance, it would seem more logical to use a hash. After all, it would be easy to set up a hash with entries for “Home,” “Tools,” and “Antimatter.” 

The value for each hash entry would then be an array. The downside is that a hash doesn’t guarantee the order in which the keys are stored, which makes it problematic to retrieve the breadcrumb entries in the proper order. So, the hash is out as a solution.

Note: Hash order is not guaranteed in Ruby 1.8.x. However, in Ruby 1.9 the hash order will be preserved, which will potentially make hashes a lot more useful.

Conclusion

We’ve ended up with a relatively simple set of methods for generating breadcrumbs. It probably doesn’t handle all cases, but it handles most of the likely ones. As a fall-back, users can explicitly provide a URL for the link, which should allow users to handle cases where controller and action are not sufficient to build a full URL for the link.

It’s not an ideal solution, though. A high proportion of users are likely to want to generate a trail in a controller, which this code doesn’t support. Plus, the array syntax for defining a breadcrumb trail still seems a little cumbersome, though still workable.

In Part 2 of this article, we’ll look at some ways to futher improve this solution.

Scotland Trip

David and Sally Keener toured Scotland, Sally’s homeland, from May 14th to May 27th. Highlights included a highland journey to scenic Loch Lomond, dinner at the famous Drover’s Inn, a guided tour of the Cruacha Power Station (a water-based electrical generating plant tunneled into a granite mountain), shopping in Glasgow and many pubs. The top restaurant for this trip was the River House, situated next to a small lake and literally within view of Stirling Castle.

River House

Note: (2018/01/13) The River House was an elegant restaurant in Sterling, Scotland. It sat on the shore of a small lake with Sterling Castle looming beside it on its steep, commanding hill. I was sad to learn recently that it had closed.

RubyNation 2008 Progress Report

Plans for RubyNation, a new regional conference serving metropolitan DC and surrounding areas, is progressing nicely. The venue and budget have been finalized. The Call for Papers just closed earlier this week, and final selection of speakers will be done in a couple of days. Finally, registration will be opening shortly for this two-day conference, which will start on August 1, 2008.

On the Steering Committee for RubyNation

RubyNation Speaker Badge I was honored to be asked to join the Steering Committee for RubyNation.org, which is a new, regional Ruby Conference that will be held in the DC metropolitan area this year. The organization is headed up by a sterling group of people, who I have already worked with in various capacities. Naturally, I accepted, even though I realize it’s going to be a lot of work. We’re expecting not only to run a successful conference this year, but we’re also hoping to make it an annual event.

JFreeChart Presentation for NovaJUG

I will be presenting for the Northern Virginia Java Users Group (NovaJUG) on April 9, 2008. The topic will be “Creating Dynamic Charts With JFreeChart.” I’ve given this talk several times for AOL during my recent tenure there, so the presentation is already available in PDF form on my Presentations page. See the NovaJUG web site for directions to the meeting location at the FGM headquarters in Reston. The talk begins at 7:00 PM, although the (optional) networking activities begin around 6:30 PM.

Regional Ruby Conference (2008)

The as-yet-unnamed regional Ruby conference being planned by the NovaRUG has been tentatively scheduled for June 28th. Right now, it’s planned as a one-day event, although I’m hopeful that it will expand to a two-day event. Expansion to two days would, of course, increase my chances of being one of the speakers.