Quick and dirty tabs on Ruby on Rails

For my Ruby on Rails pet project Is it Science Fiction? I’ve reached that point when I wanted to show tabs. You know, for the menu, on top of the page. I quickly wrote something like:

<ul class="tabs">
  <li><%= link_to 'Home', root_url %></li>
  <li><%= link_to 'Recommend', new_item_url %></li>
  <li><%= link_to 'Ranking', items_url %></li>
  <% if session[:user_name] -%>
    <li><%= link_to 'Log out', session_url, :method => :delete %></li>
    <li><%= link_to 'My Profile', edit_profile_url %></li>
  <% else %>
    <li><%= link_to 'Log in', new_session_url %></li>
  <% end %>
</ul>

and styled it like the Listamatic Unraveled CSS tabs. And everything was good, except that the current tab wasn’t highlighted. Highlighting it is a matter of setting the correct class for it.

For that I created a new version of link_to that adds the “current” class to a link if it points to the current page. That is not very hard actually, but you have to consider that some tabs, like Ranking, are not only highlighted when that page is show, but when any subpage (like a ranked item) is shown as well. After trying many solutions (in an effort to find the simplest one) I’ve settled for link_to2 and the tabs now look like this:

<ul class="tabs">
  <li><%= link_to2 'Home', root_url %></li>
  <li><%= link_to2 'Recommend', new_item_url %></li>
  <li><%= link_to2 'Ranking', items_url, {:extra_current => {:controller => :items, :action => :show}} %></li>
  <% if session[:user_name] -%>
    <li><%= link_to 'Log out', session_url, :method => :delete %></li>
    <li><%= link_to2 'My Profile', edit_profile_url %></li>
  <% else %>
    <li><%= link_to2 'Log in', new_session_url %></li>
  <% end %>
</ul>

Look at the Ranking tab, it has an extra_current that adds other pages to be treated as current. The code to do this is the following (I’ve put it in application_helper.rb):

module ApplicationHelper
  def link_to2(*args, &block)
    if block_given?
      options      = args.first || {}
      html_options = args.second || {}
    else
      name         = args.first
      options      = args.second || {}
      html_options = args.third || {}
    end

    if current_page?(options) or as_array(html_options[:extra_current]).any? {|o| current_page2? o}
      html_options[:class] = add_class(html_options[:class], "current")
    end

    html_options.delete(:extra_current)

    if block_given?
      link_to(options, html_options, &block)
    else
      link_to(name, options, html_options, &block)
    end
  end

  private

  def add_class(classes, new_class)
    ((classes or "").split(" ") << new_class).join(" ")
  end

  def as_array(o)
    if o == nil
      []
    elsif not o.is_a? Array
      [o]
    else
      o
    end
  end

  # current_page? of {:controller => :blah, :action => :bleh} when the routes also require an id raises a route error. current_page2? doesn't.
  def current_page2?(p)
    current_page? p
  rescue
    return false
  end
end

Feel free to pick the code and use it in any way you want. I’m thinking of turning it into a gem, but I need a better name than link_to2, any ideas?

Advertisements

One Reply to “Quick and dirty tabs on Ruby on Rails”

  1. we r install a downloading tab (total files) in my ruby on rails first project….. 1st tab is working correctly. but we don’t know how to redirect 2nd tab to a text editor…. i hope u will suggest me the code as early as possible

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s