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

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 %>

Related

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

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>

Best way to highlight current page in Rails 3? -- apply a css class to links conditionally

For the following code:
<%= link_to "Some Page", some_path %>
How do I apply a css class current using the current_page?‎ helper method?
Or if some other better way is available?
In app/helpers/application_helper.rb
def cp(path)
"current" if current_page?(path)
end
In your views:
<%= link_to "All Posts", posts_path, class: cp(posts_path) %>
Basically write a simple wrapper around it. Additionally you could extend the method to allow additional classes to be applied by adding arguments. Keeps the views concise/dry. Or, without extending the method, you could just do simple String interpolation like so to add additional classes:
<%= link_to "All Posts", posts_path, class: "#{cp(posts_path)} additional_class" %>
In my case I have a lot of name spaced controllers, that is why I like to show if the current view also is in the Menu Path, I had use the solution of Michael van Rooijen and then I customize for my case.
Helper
def cp(path)
"current" if request.url.include?(path)
end
View
<%= link_to "All Posts", posts_path, class: cp(posts_path) %>
Now if my menu bar is /users and my current page is /users/10/post also the link /users is set with "current" class
I branched off of Michael's answer and tweaked the helper:
def active_class?(*paths)
active = false
paths.each { |path| active ||= current_page?(path) }
active ? 'active' : nil
end
Here's how you'd use it:
<%= link_to "Bookings", bookings_path, class: active_class?(bookings_path) %>
You can pass multiple paths to it in case you have a tab which could be rendered by multiple views:
<%= content_tag :li, class: active_class?(bookings_path, action: 'new') %>
And the great thing about this is if the conditions are false, it will insert nil. Why is this good? Well, if you provide class with nil it won't include the class attribute on the tag at all. Bonus!
In the interest of not having to repeat your self too much by having to check current_page inside the link_to method all the time, here's a custom helper that you can use (put this in app/views/helpers/application_helpers.rb
def link_to_active_class(name, active_class_names, options = {}, html_options = {}, &block)
html_options[:class] = html_options[:class].to_s + active_class_names if current_page?(options.to_s)
link_to name, options, html_options, &block
end
Example usage:
<div> <%= link_to_active_class('Dashboard', 'bright_blue', dashboard_path, class: 'link_decor') </div>
if you are on http://example.com/dashboard, then it should return:
<div> <a href='/dashboard' class='link_decor bright_blue'>Dashboard</a> </div>
Regards.
I'd do it this way :
<%= link_to "Some Page", some_path, :class => current_page? ? "current" : "" %>
I tried to combine a couple of the mentioned techniques with my own needs.
def current_page(path)
'current' if current_page?(path)
end
def create_nav_link(string, path, method)
link_to string, path, data: { hover: string }, method: method
end
def create_nav_item(string, path, method = nil)
content_tag :li, create_nav_link(string, path, method), class: current_page(path)
end
Basically it allows you to use it like this:
create_nav_item("profile", profile_path) which will result in:
<li>Profile</li>,
or <li class="current">Profile</li> if this is the current page.
I didn't use request.url.include?(path) since it will also always highlight the "Home" button, and I couldn't think of a work around by far.
A variant to Eric Boehs solution (the most robust one IMHO), if you are linking directly to an object of the class (i.e. you don't show the index), with an added application helper:
def booking_link
Booking.find(8)
end
You can use the following in the view (the dd is used in the context of zurb foundation)
<%= content_tag :dd, link_to(t('hints.book'), booking_link), class: active_class?(booking_path) %>-
I think if would be good idea if you generate whole link_to from your helper method. Why to repeat the same code ( :-) DRY principle)
def create_link(text, path)
class_name = current_page?(path) ? 'current' : 'any_other_class'
link_to text, path, class: class_name
end
Now you can use like:
<%= create_link 'xyz', any_path %> (in views) which would render as xyz
Hope it helps!

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)

Highlight tab in menu

I have a menu which is a ul
Home | Calendar | Settings
I want to highlight (via a css class) the selected tab in the menu.
Some links (Home and Calendar) also have subselections
Home | *Calendar* | Settings
-------------------------
Add event | Edit event
Ofcourse when edit event is selected, Calendar should still be highlighted.
how can I best approach this using rails and css?
Thanks
The simplest way would be to check which controller is being used. I made up controller names, so of course you would replace 'home', 'calendar', and 'settings' with the correct names.
<ul>
<li class="<%= "highlighted" if params[:controller] == "home" %>">Home</li>
<li class="<%= "highlighted" if params[:controller] == "calendar" %>">Calendar</li>
<li class="<%= "highlighted" if params[:controller] == "settings" %>">Settings</li>
</ul>
In your helper file:
def is_active?(page_name)
"active" if params[:action] == page_name
end
In the template file:
link_to 'Home', '/', :class => is_active?("index")
link_to 'About', '/about', :class => is_active?("about")
link_to 'contact', '/contact', :class => is_active?("contact")
I found this on: http://juliocapote.com/post/52081481/highlight-link-based-on-current-page-in-rails
I settled on this solution which I like a lot:
In the helper
def active_if(options)
if params.merge(options) == params
'nav-active'
end
end
And in the view define what makes the route unique:
<%= link_to 'Home', root_path, class: active_if(action: 'home') %>
<%= link_to 'Aricles', articles_path, class: active_if(controller: 'articles') %>
I have the same problem and end up creating helper.
basicly it replace the link_to url helper so it wrap the link with li and add class "menu_selected" if the current controller matches the link controller
usage sample
<%= menu_link_to "Home", home_path %>
def menu_link_to(*args, &block)
url = args[1]
mapping = ActionController::Routing::Routes.recognize_path(url)
class_property = "menu_selected" if mapping[:controller] == controller.controller_path
content_tag :li, :class => class_property do
link_to *args, &block
end
end
Update to #ahmy's answer for Rails 3.2:
def menu_list_item(*args, &block)
url = args[1]
mapping = Rails.application.routes.recognize_path(url)
li_class = 'active' if mapping[:controller] == controller.controller_path
content_tag :li, :class => li_class do
link_to *args, &block
end
end
i.e. Rails.application.routes.recognize_path instead of ActionController::Routing::Routes.recognize_path.

Resources