Highlight tab in menu - ruby-on-rails

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.

Related

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

Rails way to make a horizontal menu

I want to ask you about best rails way to create a menu.
I should to make a horizontal menu. Every page belongs to the specific item of this menu and this item should has id="current" when user opens on this page.
<ul>
<li id="current">Home</li>
<li>About us</li>
</ul>
As I understand I should to create a special helper which will create this html markup and use this helper with special parameter on every view of every page. Maybe there is a better rails way to do this?
PS. Update
My solution:
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :open_most_important
protected
def open_most_important
#menu = {
:cases => { :name => 'Cases', :link => '/cases'},
:groups => { :name => 'Groups', :link => '/groups' },
:projects => { :name => 'Projects', :link => '/projects' },
:settings => { :name => 'Settings', :link => '/settings' },
:about => { :name => 'About us', :link => '/about' }}
#current_menu_item = :cases
end
The fragment of the layout application.html.erb:
<div id="menu">
<ul>
<% #menu.each do |item, value| -%>
<% if #current_menu_item == item -%>
<li id="current"><%= value[:name] %></li>
<% else -%>
<li><%= value[:name] %></li>
<% end -%>
<% end -%>
</ul>
</div>
After I need to set #current_menu_item for every controller in the before_filter
If I understand correctly you want this menu to appear on every page. If that is the case you can just add it to your layout. If you don't understand layouts read up on them at Ruby on Rails Guides http://guides.rubyonrails.org/getting_started.html#customizing-the-layout
This is how I tend to do it:
<%= menu_item("Home", root_path) {
controller.controller_name == "pages" &&
controller.action_name = "home" } %>
<%= menu_item("About us", page_path("about") {
controller.controller_name == "pages" &&
controller.action_name == "about" } %>
The helper:
def menu_item(name, url, options = {})
if yield
options["id"] = "current"
end
link_to name, url, options
end
The "id" will be "current" if the block passed to menu_item returns true.
The way I handle it is to put this in a navigation partial:
<%= nav_link "All Users", users_path, active_tabs.include?('all_users') %>
<%= nav_link "Add User", new_user_path, active_tabs.include?('add_user') %>
And then this helper at the top of each view:
<%= nav 'nav_partials/users_tabs', 'all_users' %> # one view
<%= nav 'nav_partials/users_tabs', 'add_user' %> # another view
And the helpers:
def nav_link(title, path, active, options = {})
if active
options[:class] ? options[:class] += " active" : options[:class] = "active"
end
link_to(title, path, options)
end
def nav(partial, *active_tabs)
partial = "#{params[:controller]}/nav_partials/#{partial}" unless partial.chars.first == '/'
render :partial => partial, :locals => { :active_tabs => active_tabs }
end
To me, it is elegant, even though there are some things that could be a bit better (like the file path thing in the nav helper, as well as referencing params in the helper). But it works very nicely, and it's very flexible.

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