views:

265

answers:

5

Hi All-

I have a list of tabs at the top of my application that I include in a general layout in application.html.erb. They look like this:

<li class="current"><%= link_to "Home", provider_path(current_user.id), :method=> "GET"%> </li>
            <li><%= link_to "Edit Profile", edit_student_path(current_user.id) %> </li>
      <li><%= link_to "Search", provider_search_path %> </li>

I want to change the selected tab to the "current" one, when I hit that page. So when I click Edit Profile and the Edit Profile page loads, the tabs should appear as follows:

<li><%= link_to "Home", provider_path(current_user.id), :method=> "GET"%> </li>
 <li class="current"><%= link_to "Edit Profile", edit_student_path(current_user.id) %> </li>
  <li><%= link_to "Search", provider_search_path %> </li>

Is there a way to do this outside of adding javascript to the page which is displayed? Or if there is what is generally best practice for doing this in the DRYest way possible.

Thanks

A: 

When you switch pages you could pass something like @current_tab back to the erb from the controller methods. Then use @current_tab to decide which li should be the current class. Alternatively, you could give each li and id or some unique attribute and simply change the class with your JavaScript framework of choice.

r-dub
A: 

I'm so not claiming this is the best way to do this, however I am brave enough to post what I came up with :)

Some example menu links from my layout:

<li class="nav-calendar"><%= menu_link_to 'teachers', 'show_date', 'Calendar', calendar_url  %></li>
<li class="nav-announcements"><%= menu_link_to 'announcements', nil, 'Announcements', announcements_path %></li>

Then I created this helper:

def menu_link_to(*args, &block)
  controller = args.shift
  action = args.shift

  if controller == controller_name && (action.nil? || action == action_name)
    if args.third.nil?
      args.push({:class => 'selected'})
    else
      args.third.merge!({:class => 'selected'})
    end
  end

  link_to *args, &block
end
Andy Gaskell
Andy-Thanks for your response. Quick question: Where are you coming up with the controller_name and action_name used for comparisons?Thanks.
http://api.rubyonrails.org/classes/ActionController/Base.html - Put this method in your ApplicationHelper and it'll work. Nothing against the other answers, but once you try them give mine a shot, it's a little more DRY IMO - keeps all the logic in one place instead of on every menu item which keeps the view clean.
Andy Gaskell
+3  A: 

You could try something like:

<li class="<%= controller.controller_path == 'provider' ? 'current' : '' %>"><%= link_to "Home", provider_path(current_user.id), :method=> "GET"%> </li>
<li class="<%= controller.controller_path == 'student' ? 'current' : '' %>"><%= link_to "Edit Profile", edit_student_path(current_user.id) %> </li>
<li class="<%= controller.controller_path == 'search' ? 'current' : '' %>"><%= link_to "Search", provider_search_path %> </li>

...and just check which controller you're coming from.

kchau
KChau-Thanks for this answer. It makes sense intuitively, but what if two tabs come from the same controller? I don't think there is a controller.controller_action method, so where do we go from there?
For tabs that are from the same controller, for those specific ones you may just want to pass a @current value back to the view. I can't think of a more DRY way to do it off the top of my head. If I do, I'll be sure to post.
kchau
Dave, if your action is in your url params, or something identify the url path you came from, you could use that in the view as well... so if you knew your action from the URL you could do something like: <li class="<%= params[:action] == 'whatever' ? ... and so on.
kchau
So apparently there is a method controller.action_name which solves all of our problems. I had to give the check below for coming up with complete answer, but I went ahead and upvoted your answer. Appreciate the work.
A: 

You can use controller.class == and controller.action_name == to figure out exactly which controller and action you are on

so it would be something like

<li class="<%= controller.class == ProviderController and controller.action_name == 'show' ? 'current' : '' %>"><%= link_to "Home", provider_path(current_user.id), :method=> "GET"%> </li>
<li class="<%= controller.class == StudentController and controller.action_name == 'edit' ? 'current' : '' %>"><%= link_to "Edit Profile", edit_student_path(current_user.id) %> </li>
<li class="<%= controller.class == ProviderController and controller.action_name == 'search' ? 'current' : '' %>"><%= link_to "Search", provider_search_path %> </li>

I believe there are some ways to get the current url for the page you are on, but then your "active" styling will be dependent on only getting to that action via that path, which may not always be the case depending on the routes, this way will ensure the view shows what is true based on what was actually run, not what the url is in the address bar

danivovich
Ahh thanks. This controller.action_name is exactly what I needed. I will give this one a check since its the final solution, but I wish I could give half and half.
Nice job, danivo.
kchau
A: 

You could just do this:

<%= current_page?(:controller => 'your_controller', :action => 'index') ? 'current' : '' %>
Adam Dorsey