In rails how to detect sub pages with if current_page? - ruby-on-rails

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

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.

Rails: how to pass OR statement into current_page method?

I have the following code that denotes an active tab whenever the user is on a certain subpage, in this case the Users index view.
<li class="<%='active' if current_page?(users_path) %>">
<%= link_to 'Users', users_path %></li>
I'd like it so that the tab is shown as "active" whenever the user is on any of the show, edit, OR index pages.
I tried something like this:
<li class="<%='active' if current_page?(users_path || edit_user_path || user_path) %>">
<%= link_to 'Users', users_path %></li>
But only users_path is recognized.
What's the correct way to build an OR statement into the current_page method?
that should be
<li class="<%='active' if current_page?(users_path) || current_page?(edit_user_path) || current_page?(user_path) %>">
this will be hard to maintain if you're doing this to a lot of pages. You are better of using a gem for semantic navigation.
This is some code I've used in previous apps.
def nav_item(copy, link)
content_tag :li, class: nav_class(link) do
link_to copy, link
end
end
def nav_class(page)
case page
when :users then 'active' if request.path.match(/^\/users/)
when :projects then 'active' if request.path.match(/^\/projects/)
else
nil
end
end
The two helper methods above will render a link inside a li tag with class="active" if the route matches the current path.
Not on a UsersController action:
<%= nav_item('Users', :users) %> #=> <li>Users</li>
On a UsersController action:
<%= nav_item('Users', :users) %> #=> <li class="active">Users</li>

Set <li> active class in Rails based on URL param

I've got a nav like this:
<nav>
<ul class='nav nav-pills'>
<li>
<%= link_to 'link1', '#' %>
</li>
<li>
<%= link_to 'link1', '#' %>
</li>
</ul>
</nav>
My routes, view and controller are set up such that root_url/.../action and root_url/.../action/:page_id will both render the same view, with an instance variable #page being set based on the :page_id param or to a specified default for the action's root. Later in the view, I'm rendering a partial that matches the name of #page.
What I'm trying to do is set class='active' on the <li> whose link text matches the value of #page.
My original inclination was to stay DRY and set window.page_id to match #page and use CoffeeScript to add the class, but that gave me a very noticeable delay between the page loading and the class being set.
Does anyone know the best method of accomplishing this? Right now I'm putting embedded ruby in each one of the <li> elements, which is rather undesirable.
Borrowed and slightly modified to fit your needs from another S.O. post Best way to add "current" class to nav in Rails 3
def nav_link(link_text, page)
class_name = link_text == page ? 'active' : ''
content_tag(:li, :class => class_name) do
link_to link_text, page
end
end
used like:
nav_link 'Home', #page
Expanding on Zeiv's answer, you can just compare the url:
Helper Method:
def nav_link(link_text, link_path)
content_tag(:li, class: ('active' if link_path == url_for(only_path: true)) ) do
link_to link_text, link_path
end
end
Now in the view you can do this:
<%= nav_link "Some Page", some_page_path %>
Expanding on 99miles's answer, I put this in the corresponding helper:
def nav_link(link_text, link_path, current_page)
content_tag(:li, class: ('active' if link_text.downcase.gsub(' ', '_') == current_page) ) do
link_to link_text, link_path
end
end
That way <li> elements that aren't active don't have an empty class, and it works even when the link text contains spaces.
Used in the view like:
<%= nav_link "My Page", page_path('my_page'), #page %>
Edit:
Or, if you want to specify the text of the link independently from the :page_id
def nav_link(link_text, link_path, page_id, current_page)
content_tag(:li, class: ('active' if page_id == current_page) ) do
link_to link_text, link_path
end
end
Then you can do
<%= nav_link "My Link", page_path('my_page'), 'my_page', #page %>

Refactor simple rails code for specifying active li on navigation

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>

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