views:

70

answers:

3

I'm still a beginner with ruby and rails, and now I'm googling about methods for creating a tabbed menu, marking the list element of the currently active controller with a css class "current". There are many hits on google, but I haven't found any that I manage to get working.

I have my menu here:

<ul>
  <li class="current"><%= link_to 'Home', root_path %> </li>
  <li><%= link_to 'Browse songs', page_path('browse') %> </li>
  <li><%= link_to 'Add song', new_song_path %> </li>
  <li><%= link_to 'Request song', artists_path %> </li>
  <li><%= link_to 'My ReChord', artists_path %> </li>
  <li><%= link_to 'Help', page_path('help') %> </li>
  <li id="search"><form><input type="search" placeholder="Type here to find a song or an artist"/></form> </li>
  <li class="notab">
    <% if user_signed_in? %>
      <%= link_to 'Sign out', destroy_user_session_path %>
    <% else %>
      <%= link_to 'Sign in', new_user_session_path %> or
      <%= link_to 'sign up', new_user_registration_path %>
    <% end %>
  </li>
</ul>

Now I have class="current" hard coded on the Home tab. However, when clicking for example Browse songs, I want the class="current" to be moved to the corresponding list element for that line.

Note that I have some links that just is the route path (like new_song_path) and some links that are sub pages, like page_path('help'). I need it to work for both these types of links.

Can you provide me with either a good tutorial suitable for my two days long experience with rails, or (preferably) example code that might fit perfectly on my list above? Thanks in advance!

+1  A: 

Create a helper to build that menu for you:

def menu_builder(page_id)
  tabs = ['home','store','faq']
  content = ""
  tabs.each do |tab|
    content << if page_id == tab
      content_tag('li', content_tag('a', tab, :href => nil ), :class => 'current') + " "
    else
      content_tag('li', content_tag('a', tab, :href => "/#{tab}" )) + " "
    end
  end
  content
end

Or my own short version of it:

def menu_builder(page_id)
   ["home", "store", "faq"].map { |tab| 
       %{<li class="#{page_id == tab ? "active" : "inactive"}"><a href="#{tab}">#{tab.capitalize}</a></li>}  
   }.join("\n")
end

page_id is an identifier of some page and should be defined in your controllers.

class Foo < ApplicationController

    def faq
        @page_id = 'faq'
        ...
    end
end

Then just use it in the template:

<ul>
    <%= menu_builder(@page_id) %>
    <li class="search">...</li>
</ul>
floatless
+1  A: 

If you want something more flexible, checkout the tabs_on_rails plugin I created to solve exactly this common pattern.

In your template use the tabs_tag helper to create your tab.

<% tabs_tag do |tab| %>
  <%= tab.home      'Homepage', root_path %>
  <%= tab.dashboard 'Dashboard', dashboard_path %>
  <%= tab.account   'Account', account_path %>
<% end %>

The example above produces the following HTML output.

<ul>
  <li><a href="/">Homepage</a></li>
  <li><a href="/dashboard">Dashboard</a></li>
  <li><a href="/account">Account</a></li>
</ul>

The usage is similar to the Rails route file. You create named tabs with the syntax tab.name_of_tab.

The name you use creating a tab is the same you’re going to refer to in your controller when you want to mark a tab as the current tab.

class DashboardController < ApplicationController
  set_tab :dashboard
end

Now, if the action belongs to DashboardController, the template will automatically render the following HTML code.

<ul>
  <li><a href="/">Homepage</a></li>
  <li class="custom"><span>Dashboard</span></li>
  <li><a href="/account">Account</a></li>
</ul>
Simone Carletti
Thanks! But how can I make it work with page_path('browse') and page_path('help'), which are to be two different tabs?
Johan
I mean, I have one controller called page. In the controller, I have a function called show. In that function, I do render :partial => params[:id]. I would need to run set_tab with a dynamic parmeter in some way. I'm completely new to rails.
Johan
You can call set_tab in your action or use a before_filter.
Simone Carletti
Okay, but I mean, how can I use set_tab with a dynamic value? I mean, I have only one action with a render :partial => params[:id]. I want like set_tab params[:id], but that does not seem to work.
Johan
Yes, you can do this. But the in your template you need to configure a tab.<ID_NAME> for each possible ID. Did you read the documentation?
Simone Carletti
+2  A: 

Hi Johan

Take a look an this plugin

http://github.com/paolodona/rails-widgets

Its has lots of cool components including navigation

documentation http://wiki.github.com/paolodona/rails-widgets/

cheers

sameera

sameera207
Big fan of the widgets' tabnav -- have used it on many projects
Jonathan