Goose is a navigation plugin for Rails whose aim it is to make adding smart, context-aware navigation to your application as easy as possible.
First of all, install it with bundler.
In your Gemfile
:
gem 'goose'
Then:
$ bundle install
Now, install the Goose configuration:
$ rails generate goose:install
Create a partial for each navigation menu in the [now present]
app/views/nav
directory. You can have as many as you like.
We add one in app/views/nav/_main.html.erb
:
<nav>
<ul>
</ul>
</nav>
You'll notice this example uses HTML5 <nav>
tags. You don't have to
(but you probably should).
In your <ul>
, use nav_to
in place of your <li>
s. nav_to
is
invoked the same way as the link_to
helper you already know and love:
<nav>
<ul>
<%= nav_to 'People', people_path %>
<%= nav_to 'Places', places_path %>
<%= nav_to 'Things', things_path %>
</ul>
</nav>
If your navigation items are more complex, use the block form of
nav_to
:
<nav>
<ul>
<%= nav_to 'People' do %>
<%# Inside the 'People' <li> %>
<% end %>
<%= nav_to 'Places', places_path %>
<%= nav_to 'Things', things_path %>
</ul>
</nav>
Now, in each action template, just tell Goose where you are.
<%= nav_at 'People' %>
By default, Goose guesses your location is in reference to a "main"
nav. You can tell it to use something else easily enough; for
instance, if we also had a app/views/nav/_people.html.erb
that we
were using as secondary navigation:
<%= nav_at 'Address Information', in: 'people' %>
The navigation partial will be inserted (as you might expect), exactly
where you put your nav_at
. If you want to place your navigation
somewhere else (as you probably want to do with your main navigation),
just wrap your navigation partial in a content_for
:
<% content_for :main_navigation do %>
<nav>
<ul>
<%= nav_to 'People', people_path %>
<%= nav_to 'Places', places_path %>
<%= nav_to 'Things', things_path %>
</ul>
</nav>
<% end %>
And use yield
wherever it makes sense in your layout:
<!DOCTYPE html>
<html>
...
<header>
<h1>Great balls of fire!</h1>
<%= yield :main_navigation %>
</header>
...
</html>
It's that simple.
Let's say we had navigation that looked like:
<% content_for :main_navigation do %>
<nav>
<ul>
<%= nav_to 'People', people_path %>
<%= nav_to 'Places', places_path %>
<%= nav_to 'Things', things_path %>
</ul>
</nav>
<% end %>
In our action templates, we would usually use nav_at
to indicate the
currently active navigation item:
<%= nav_at 'Places' %>
We could give it even more detail if we'd like breadcrumbs. In this example we're looking at a page for an arrondissement in Paris:
<%= nav_at 'Places', 'Paris', 'Enclos-St-Laurent' %>
This nav_at
invocation will still render the main
partial in
app/views
, we just need to add a content_for
for breadcrumbs.
We'll make it a simple list that we can style later with CSS:
<% content_for :breadcrumbs do %>
<nav id='breadcrumbs'>
<ul>
<% breadcrumbs.each do |crumb| %>
<li><%= crumb %></li>
<% end %>
</ul>
</nav>
<% end %>
Remember, we need to tell the layout where to put the breadcrumbs.
We just defined the content for :breadcrumbs
, so we'll add a
matching yield
to our application.html.erb
:
<%= yield :breadcrumbs %>
If we run this and pull up the page in a browser, we'll notice that
only the Places
breadcrumb is a link (it automatically picked it up
from the nav_to
in the main nav, handy!) -- if we want the other
breadcrumbs to be linked (usually all but the last), we can pass the
URLs as well:
<%= nav_at 'Places', ['Paris', place_path(@paris)], 'Enclos-St-Laurent' %>
Now both Places
and Paris
are linked.
See config/initializers/goose.rb
for options.
Copyright (c) 2010-2011 Bruce Williams. See LICENSE for details.