Simple Navigation in Rails

Most web applications call for at least one level of navigational structure. Many will have two or more levels and require the active node in each level to have distinct styling via an active class. I’ve seen as many navigation solutions as I’ve seen rails projects. Most look similar in that each level of navigation is represented by a partial. Some track the active node via local variables passed with the call to render, but this approach isn’t very DRY. Some track the active node via instance variables on the controller, but this is a painful violation of MVC which gets especially tedious to maintain in multilevel scenarios.

Thankfully, there’s a mature, simple, and actively maintained solution just a gem away. Simple Navigation handles just about whatever you can throw at it. I was surprised, however, by how hard it was to unearth when I was looking for the solution to my navigational troubles. It’s an elegant solution that deserves more attention.

With Simple Navigation, the application’s entire navigational structure is contained in a single configuration file. The configuration is specified in a simple DSL that allows for multiple levels of navigation. You can render the entire structure, with appropriate sub menus with a call to render_navigation or you can render each level explicitly with calls to render_navigation :level => 2. There is, of course, support for configuring the exact classes, elements, and ids used in the HTML.

Active item tracking can be done automatically, which works surprisingly well in basic cases. Alternatively, you can supply a regular expression or proc to determine which item should be tracked as active. If your navigation has more than one level, then the parent of an active item will also be marked as active.

The project wiki has good documentation for most features. There are a lot of options, but the configuration is still easily understood. For instance, here’s a chunk of the configuration for my current project. The navigation features a static top bar with any applicable secondary menu rendered as tabs below. The entire ‘Admin’ menu is visible only to users who are administrators.

SimpleNavigation::Configuration.run do |navigation|
  navigation.autogenerate_item_ids = false
  navigation.selected_class = 'active'

  navigation.items do |primary|
    primary.item :schedule, 'Schedule', schedules_path

    primary.item :admin, 'Admin', admin_root_path, :if => Proc.new { current_user.administrator? } do |admin|
      admin.item :admin_shifts, 'Shifts', admin_shifts_path, :highlights_on => /admin\/?$|admin\/shifts/i
      admin.item :admin_responsibilities, 'Responsibilities', admin_responsibilities_path, :highlights_on => :subpath
      admin.item :admin_locations, 'Locations', admin_locations_path, :highlights_on => :subpath
      admin.item :admin_holiday_schedules, 'Holidays', admin_holiday_schedules_path, :highlights_on => :subpath
      admin.item :admin_users, 'Users', admin_users_path, :highlights_on => :subpath
      admin.dom_class = 'tabs span16'
    end

    primary.item :preferences, 'Preferences', preferences_path
    primary.item :help, 'Help', help_path
    primary.dom_class = 'nav'
  end
end

Check out Simple Navigation for use in your Rails projects. It’s simple, powerful, and DRY.