Ruby on rails and tabs

14,615

Solution 1

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>

Solution 2

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>

Solution 3

Take a look an this plugin:

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

It has lots of cool components including navigation.

Documentation: https://github.com/paolodona/rails-widgets/wiki

Solution 4

I created tabulous to solve this problem. There is a separate tab configuration file where you can describe how you want your tabs to behave. For example:

Tabulous.setup do

  tabs do
    pictures_tab do
      text          { 'Pictures' }
      link_path     { pictures_path }
      visible_when  { true }
      enabled_when  { true }
      active_when   { in_action('any').of_controller('pictures') }
    end

    music_tab do
      text          { 'Music' }
      link_path     { songs_path }
      visible_when  { true }
      enabled_when  { current_user.has_music? }
      active_when   { in_action('any').of_controller('songs') }
    end

    profile_tab do
      text          { 'My Profile' }
      link_path     { account_path(current_user) }
      visible_when  { true }
      enabled_when  { true }
      active_when   { in_actions('show', 'edit', 'update').of_controller('accounts') }
    end
  end

end

Read the tabulous documentation to learn more.

Share:
14,615

Related videos on Youtube

Johan
Author by

Johan

I'm a curios programmer too.

Updated on June 04, 2022

Comments

  • Johan
    Johan almost 2 years

    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!

  • Jonathan
    Jonathan over 13 years
    Big fan of the widgets' tabnav -- have used it on many projects
  • Johan
    Johan over 13 years
    Thanks! But how can I make it work with page_path('browse') and page_path('help'), which are to be two different tabs?
  • Johan
    Johan over 13 years
    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.
  • Simone Carletti
    Simone Carletti over 13 years
    You can call set_tab in your action or use a before_filter.
  • Johan
    Johan over 13 years
    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.
  • Simone Carletti
    Simone Carletti over 13 years
    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?
  • Teemu Leisti
    Teemu Leisti almost 11 years
    I'd like to add a recommendation for Tabulous. I've been using it for a while now, and it's a very good gem.
  • broschb
    broschb over 9 years
    I had to add .html_safe to the return from menu_builder(page_id) method to get this to work

Related