Refactor simple rails code for specifying active li on navigation - ruby-on-rails

I am trying to set an li class of active based on what page the user is on.
I have 4 navigation elements and they all look something like this:
<% if #activeLi == "home" %>
<li class="active">
<% else %>
<li>
<% end %>
<%= link_to :controller => "home" do %>
<span>Home</span>
<% end %>
</li>
and then in each controller I just set #activeLi like this:
def index
#activeLi = "about"
end
I know this is pretty basic stuff, but i'm just wondering if there is an easier way to do this?

Well I know one way you can simplify this and thats by getting rid of the need to use those nasty instance variables.
<li class="<%= controller_name == "home" ? 'active': '' %>">
<%= link_to :controller => "home" do %>
<span>Home</span>
<% end %>
</li>

Related

Ruby use conditional operator to check current path

I'm trying to create a navbar that highlights the li item on which page I am.
In my code below I'm trying to use a conditional operator to see if the current path is correct. Or at least that's what I think i'm doing.
<li id="home-link" data-hook class="<%= root_path ? "active" : "" %>"><%= link_to Spree.t(:Home), spree.root_path %></li>
<% if spree_current_user %>
<li id="home-link" data-hook class="<%= products_path ? "active" : "" %>" ><%= link_to Spree.t(:products), spree.products_path %></li>
<% end %>
What I then expect to happen is that if i'm on the home page the li get's the class active,
what currently happens is that all li items get the class active.
How can I check the current path?
No, you are testing if the path helpers are true, and they are as they return a String. That's why active is always set.
Take a look at current_page?:
<% product_active = 'active' if current_page?(controller: 'products', action: 'index') %>
<li id="home-link" data-hook class="<%= product_active %>">
EDIT: As #NensiMakawana suggets, you can alternatively use the active_link_to gem.

In rails how to detect sub pages with if current_page?

I use current_page? to detect the current page and style that link differently like this :
<li class="snavitem <%= ' active' if current_page? countries_path %>">
Now if we are at /countries then this will add the active class to the link which will make it different. But how to style the link like this when we are in sub pages like countries/new, countries/edit ?
The simple way is smth like this:
current_page?(controller: 'countries')
countries/ #=> true
countries/anything-here #=> true
Define a method check_action in application helper
def check_action controller, action
return true if controller.eql?("countries") and (action.includes?("index") or action.includes?("edit") or action.includes?("new"))
end
In view
<li class="snavitem <%= ' active' if check_action(controller, controller.action_name) %>">
You can use request.fullpath to get current full path
example
<ul>
<% Contry.all.each do |c| %>
<li class="snavitem <%= is_active?(edit_contry_path(c)) %>">
<%= link_to "edit " + c.name, edit_contry_path(c) %>
</li>
<% end %>
</ul>
and on your application_helper.rb
def is_active?(link_path)
"active" if request.fullpath == link_path
end
read about request.fullpath here

Refactoring navbar with an active class in a partial

This is what I have and I want to include it in a partial so that I am not duplicating it in 4 places. The problem is the active class which should change based on the page the user is on. How can I go about this? Or am I better off just repeating the code in 4 templates?
<div class="navbox">
<ul class="nav">
Account</li>
<li> Profile</li>
<li> Photos</li>
<li> Security</li>
</ul>
</div>
Pass in an active local when rendering:
render :partial => 'navbox', :locals => { :active => 'Account' }
Then have this as your partial:
<div class="navbox">
<ul class="nav">
<a href="#"<% if active == 'Account' %> class="active"<% end %>> Account</li></a>
<a href="#"<% if active == 'Profile' %> class="active"<% end %>><li> Profile</li></a>
<a href="#"<% if active == 'Photos' %> class="active"<% end %>><li> Photos</li></a>
<a href="#"<% if active == 'Security' %> class="active"<% end %>><li> Security</li></a>
</ul>
</div>
There's various ways this could be cleaned-up (link_to, helper methods, etc.), which is left as an exercise. You could also potentially avoid needing to pass in a local if you can deduce whether something is “active” from the request URL.
Also have a look at link_to_unless_current & link_to_unless if you don't want to link at all instead of adding a class to the link.
Look for the active_link_to gem https://github.com/twg/active_link_to
It is the easiest way
You can try to crete helper like this:
{'Account' => account_path, 'Profile' => profile_path...etc}.each do |name, path|
content_tag :li do
link_to name, path, class: (current_page?(path) 'active' : 'regular')
end
end
Also take a look at method link_to_unless_current http://apidock.com/rails/ActionView/Helpers/UrlHelper/link_to_unless_current

How to mark a link in a layout menu as "active" in rails?

I have a ul filled with links in my layout/application.html.erb and want the current location link be marked with class="active".
Now I'm using:
<%= link_to 'About Us', { :controller => 'aboutus' }, :class => "menu#{' active' if params[:controller] == 'aboutus'}" %>
But it looks pretty nasty to me.
Anyone has a better idea?
The link_to_unless_current method doesn't actually create a link, nor does it add a class of active. If you'd still like to do that, you can use the current_page method to check if the current page matches the route you specified:
<ul id="main_nav">
<li><%= link_to "Search", search_path, :class => ('active' if current_page?(search_path)) %></li>
</ul>
Or if you'd like to add the class on the wrapping element:
<li class="<%= 'active' if current_page?(search_path) %>">
<%= link_to "Search", search_path %>
</li>
You can use the helper method similar to link_to
its called "link_to_unless_current".
http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html ( find the details here )
HTH
An example for a root path with a li tag, i tried to do it with a content_tag, but no luck for the if case in a elegant way
<li<%= " class='active'".html_safe if current_page?(root_path) %>>
<%= link_to "Home", root_path %>
</li>
i have some issues when i keep the class in blank with bootstrap(if i remember well)

Changing Current Tab in Rails

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
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
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.
Take a look at TabsOnRails
You could just do this:
<%= current_page?(:controller => 'your_controller', :action => 'index') ? 'current' : '' %>
I made a helper for this that can accept any number of arguments which is useful for nested resources, but it also accepts a single controller name just like the other answers.
application-helper.rb:
def is_active(*links)
links.each { |link| return "active" if params[:controller] == link }
end
application.html.erb:
<li class="<%=is_active('home')%>">...</li>
Or
Example usage with HAML & nested resource(will be active for any of the provided controller names):
applcation.html.haml:
%li{:class => is_active('blogs', 'comments')}
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.
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
I did this in the application helper and it seems to work fine:
def current_page(path)
"active" if current_page?(path)
end
Then call like this:
<li class="<%= current_page(root_path)%>"> <%= link_to "Home", root_path %></li>

Resources