3

So in my application.html.erb I have my navigational structure that looks something like this:

<div id="navigation">
            <ul class="pills">
                    <% if current_page?(:controller => 'welcome', :action => 'index') %>
                        <li><%= link_to "Profile", vanity_path(:vname => current_user.username) %></li>
                        <li><%= link_to "Settings", settings_path %></li>
                        <li><%= link_to "Sign Out", signout_path %></li>
                    <% elsif !current_page?(:controller => 'welcome', :action => 'index') %>
                        <li><%= link_to "Home", root_path %></li>
                        <li><%= link_to "Profile", vanity_path(:vname => current_user.username) %></li>
                        <li><%= link_to "Settings", settings_path %></li>
                        <li><%= link_to "Sign Out", signout_path %></li>              
                    <% end %>
            </ul>
        </div>

However, what I would like to do, is once they are on any of the pages in the navigation, it applies a class active to the respective link.

So for instance, if the user is on mydomain.com/johnbrown which is the Profile link, the rails helper would look something like this:

link_to "Profile", vanity_path(:vname => current_user.username), :class => "active".

But how do I do that in a programmatic way, so I am not duplicating content? i.e. how do I get that functionality for all the pages in my navigation and write it as DRY as possible?

Thanks.

marcamillion
  • 32,933
  • 55
  • 189
  • 380
  • Possible duplicate? : http://stackoverflow.com/questions/7294181/dynamic-menu-ruby-on-rails-and-partial/7294580#7294580 – Harish Shetty Oct 13 '11 at 20:34
  • Or this question? http://stackoverflow.com/questions/3705898/best-way-to-add-current-class-to-nav-in-rails-3 – kafuchau Oct 13 '11 at 20:36

5 Answers5

6

This is a really great question. I've never really been happy with the solutions I've seen or come up with. Maybe we can get one together here.

Here is what I've tried in the past

I've made a helper that returns a hash with :class defined since I use HAML

def active_tab(path)
  request.path.match(/^#{path}/) ? { :class => 'active' } : {}
end

ex usage:

= link_to "Dashboard", dashboard_path, active_tab("#{dashboard_path}$")

Or an alternative along the same lines

def active_class(path)
  request.path =~ /#{path}/ ? 'active' : nil
end

ex usage:

= link_to 'Presentations', admin_presentations_path, :class => "#{active_class('presentations')}"

I would love to see some other suggestions on this.

Matt Polito
  • 9,588
  • 2
  • 19
  • 13
  • Love this, but what would the `ERB` version look like? I can't see any differences between this version and ERB version...but given that you specified that you use HAML it is making me wonder. – marcamillion Oct 14 '11 at 23:33
3

I found this answer for a bootstrap related navbar but you could easily use it with your nav.

Answer taken from here


You can use helper for handle "current_page?", example a method :

module ApplicationHelper

 def is_active?(link_path)
  if current_page?(link_path)
    "active"
  else
    ""
  end
 end

end

example bootstrap navbar

<div class="navbar">
  <div class="navbar-inner">
    <a class="brand" href="#">Title</a>
    <ul class="nav">
      <li class="active"><a href="#">Home</a></li>
      <li><a href="#">Link</a></li>
      <li><a href="#">Link</a></li>
    </ul>
  </div>
</div>

So, on view looks like

<li class="<%= is_active?(some_path) %>">
<%= link_to "name path", some_path %>
</li>

For Haml

Just simple looks like :

%ul.nav
  %li{class: current_page?(some_path) && 'active'}
    = link_to "About Us", some_path
Community
  • 1
  • 1
Jonny
  • 431
  • 4
  • 8
1

You may define a helper method in application_helper.rb

def create_link(text, path)
  class_name = current_page?(path) ? 'my_class' : ''

  content_tag(:li, class: class_name) do
    link_to text, path
  end
end

Now you can use like:

create_link 'xyz', any_path which would render as

<li class="my_class">
  <a href="/any">xyz</a>
</li>

Hope it helps!

Dusht
  • 4,712
  • 3
  • 18
  • 24
0

I wanted a solution which was more like the link_to method and not pass an extra set of paramters. You can do this by creating a method in application_helper.rb (or create a LinkHelper) which takes in the same 2 parameters as link_to:

def tab_to(title, path)
  link_to title, path, class: active_current_page(path)
end

Then create a private method to return the 'active' class:

def active_current_page(path)
  "active" if current_page?(path)
end

Full file as link_helper.rb:

module LinkHelper
  def tab_to(title, path)
    link_to title, path, class: active_current_page(path)
  end

  private

  def active_current_page(path)
    "active" if current_page?(path)
  end
end

This can then be called like this:

tab_to "Profile", vanity_path(:vname => current_user.username)
0

Why don't you just take the redundant parts out of the if else block? Also take a look at 'link_to_unless'

 <div id="navigation">
        <ul class="pills">

                    <li><%= link_to_unless(current_page?(:controller => 'welcome', :action => 'index'), "Home", root_path %></li>

                   <li><%= link_to "Profile", vanity_path(:vname => current_user.username) %></li>
                    <li><%= link_to "Settings", settings_path %></li>
                    <li><%= link_to "Sign Out", signout_path %></li> 
        </ul>
    </div>

then I would add some jQuery to inject active class into the link that matches the window.location pattern.

Homan
  • 25,618
  • 22
  • 70
  • 107
  • This is an interesting solution. Never knew about `link_to_unless`. Thanks for that. As for the jQuery, I would rather not use JS if I don't have to...i.e. if there is a Rails way, I would rather use that first. – marcamillion Oct 14 '11 at 23:30