Need Advice: Structure Of Rails Views For Submenus?

- 1 answer

Imagine to have two RESTful controllers (UsersController, OffersController) and a PagesController (used for static content such as index, about and so on) in your application.

You have the following routes defined:

map.with_options :controller => 'pages' do |pages|
  pages.root :action => 'index'     # static home page
  pages.about :action => 'about'    # static about page
  # maybe more static pages...
map.resources :users    # RESTful UsersController
map.resources :posts    # RESTful PostsController

Your application layout looks like this:

    <title>Demo Application</title>
    <ul id="menu">
         <%= link_to 'Home', root_path %>
         <%= link_to 'Offers', offers_path %>
         <ul id="submenu>
           <li><%= link_to 'Search', 'path/to/search' %></li>
           <li>maybe more links...</li>
         <%= link_to 'About', about_path %>
         <%= link_to 'Admin', users_path %>
         <ul id="submenu">
           <li><%= link_to 'New User', new_user_path %></li>
           <li><%= link_to 'New Offer', new_offer_path %></li>
           <li>maybe more links</li>
    <%= yield %>

The problem with the layout is that I want only one #submenu to be visible at any time. All other submenus can be completely skipped (don't need to rendered at all).

Take the Admin menu for example: This menu should be active for all RESTful paths in the application except for offers_path. Active means that the submenu is visible.

The only solution I can think of to achieve this is to build a lot complicated if conditions and that sucks (really complicated to write and to maintain). I'm looking for an elegant solution?

I hope someone understands my question - if there's something unclear just comment the question and I'm going to explain it in more detail.



One thing you could play with is yield and content_for, used with a few partials for the menus. For example you could put each section of the menu in a partial and then modify your layout to something like:

<%= yield(:menu) %>

You then can then specify in your views content_for and put whatever partials you want into the menu. If it's not specified it won't get rendered.

<% content_for(:menu) do %>
   <%= render :partial => 'layouts/menu' %>
   <%= render :partial => 'layouts/search_menu' %>
 <% end %>

If you're using a lot of the same menus in most pages, specify a default in your layout if no yield(:menu) is found.

<%= yield(:menu) || render :partial => 'layouts/menu_default' %>

Saves you a lot of typing. :) I've found this to be a nice clean way of handling things.