Лучший способ добавить "текущий" класс к навигации в Rails 3

У меня есть несколько статических страниц в меню навигации. Я хочу добавить класс, например "текущий" к элементу, который в настоящее время отображается.

То, как я это делаю, заключается в том, чтобы добавить тонны вспомогательных методов (каждый для одного элемента), чтобы проверить контроллер и действие.

def current_root_class
  'class="current"' if controller_name == "homepage" && action_name == "index" 
end

<ul>
  <li <%= current_root_class %>><%= link_to "Home", root_path %>

Есть ли лучший способ сделать это!? Мой нынешний путь настолько глупый...

Ответ 1

Не совсем ответ здесь, потому что я использую то же самое, что и вы. Я только что определил вспомогательные методы для проверки нескольких контроллеров или действий:

В application_helper.rb

  def controller?(*controller)
    controller.include?(params[:controller])
  end

  def action?(*action)
    action.include?(params[:action])
  end

Затем вы можете использовать if controller?("homepage") && action?("index", "show") в своих представлениях или других вспомогательных методах...

Ответ 2

Я сделал помощника nav_link:

def nav_link(link_text, link_path)
  class_name = current_page?(link_path) ? 'current' : ''

  content_tag(:li, :class => class_name) do
    link_to link_text, link_path
  end
end

используется как:

nav_link 'Home', root_path

который будет создавать HTML как

<li class="current"><a href="/">Home</a></li>

Ответ 3

Используйте current_page? помощник, чтобы определить, следует ли назначать класс "current". Например:

<%= 'active' if current_page?(home_about_path) %>

Примечание. Вы также можете передать путь (не только хэш опций), например: current_page?(root_path).

Ответ 4

Я использую эту функцию nav_link (text, link) в application_helper.rb(Rails 3), чтобы выполнить эту работу, и она переводит мои ссылки на загрузку twitter 2.0 для меня.

def nav_link(text, link)
    recognized = Rails.application.routes.recognize_path(link)
    if recognized[:controller] == params[:controller] && recognized[:action] == params[:action]
        content_tag(:li, :class => "active") do
            link_to( text, link)
        end
    else
        content_tag(:li) do
            link_to( text, link)
        end
    end
end

Пример:

<%=nav_link("About Us", about_path) %>

Ответ 5

То, как я это сделал, - добавить вспомогательную функцию в application_helper

def current_class?(test_path)
  return 'current' if request.request_uri == test_path
  ''
end

Затем в nav,

<%= link_to 'Home', root_path, :class => current_class?(root_path) %>

Это проверяет путь ссылки на текущую страницу uri и возвращает либо текущий класс, либо пустую строку.

Я не тестировал это полностью, и я очень новичок в RoR (переход через десять лет с PHP), поэтому, если у этого есть главный недостаток, я бы хотел его услышать.

По крайней мере, вам нужно только 1 вспомогательная функция и простой вызов в каждой ссылке.

Ответ 6

Чтобы построить ответ @Skilldrick...

Если вы добавите этот код в application.js, он будет следить за тем, чтобы все выпадающие меню с активными дочерними элементами также были отмечены как активные...

$('.active').closest('li.dropdown').addClass('active');

Повторить вспомогательный код > Добавить помощник, называемый nav_link:

def nav_link_to(link_text, link_path)
  class_name = current_page?(link_path) ? 'active' : ''

  content_tag(:li, :class => class_name) do
    link_to link_text, link_path
  end
end

используется как:

nav_link_to 'Home', root_path

который будет создавать HTML как

<li class="active"><a href="/">Home</a></li>

Ответ 7

Я думаю, что лучший способ -

application_helper.rb:

def is_active(controller, action)       
  params[:action] == action && params[:controller] == controller ? "active" : nil        
end

И в меню:

<li class="<%= is_active('controller', 'action') %>">

Ответ 8

Я знаю, что это датированный ответ, но вы можете легко игнорировать все эти текущие проверки страницы с помощью связной оболочки link_to, называемой active_link_to gem, он работает именно так, как вы хотите, добавьте активный класс в текущую ссылку на страницу

Ответ 9

Вот полный пример того, как добавить активный класс на странице меню начальной загрузки в режиме просмотра рельсов.

    <li class="<%= 'active' if current_page?(root_path) %>"><%= link_to 'Home', controller: "welcome" %></li>
    <li class="<%= 'active' if current_page?(about_path) %>"><%= link_to 'About us', about_path %></li>
   <li class="<%= 'active' if current_page?(contact_path) %>"><%= link_to 'Contact us', contact_path %></li>

Ответ 10

Я использую потрясающий драгоценный камень, называемый Вкладки на Rails.

Ответ 11

Метод current_page? не достаточно гибкий для меня (скажем, вы устанавливаете контроллер, но не действие, то оно вернет true только для действия индекса контроллера), поэтому я сделал это на основе другого ответы:

  def nav_link_to(link_text, link_path, checks=nil)
    active = false
    if not checks.nil?
      active = true
      checks.each do |check,v|
        if not v.include? params[check]
          active = false
          break
        end
      end
    end

    return content_tag :li, :class => (active ? 'active' : '') do
      link_to link_text, link_path
    end
  end

Пример:

nav_link_to "Pages", pages_url, :controller => 'pages'

Ответ 12

Оп! Ознакомьтесь с этой статьей: Лучший способ добавить выбранный класс к ссылкам в рельсах

Переместите nav_link_helper.rb в app/helpers, и это может быть так же просто, как:

<%= nav_link 'My_Page', 'http://example.com/page' %>

Помощник nav_link работает так же, как стандартный Rails link_to helper, но добавляет "выбранный" класс к вашей ссылке (или ее обертке), если выполняются определенные критерии. По умолчанию, если URL-адрес назначения ссылки совпадает с URL-адресом текущей страницы, в ссылку добавляется класс "selected".

Здесь есть смысл: https://gist.github.com/3279194

UPDATE: теперь это драгоценный камень: http://rubygems.org/gems/nav_link_to

Ответ 13

У меня есть более сжатая версия nav_link, которая работает точно так же, как link_to, но настроена для вывода тега wrapping li.

Поместите следующее в свой application_helper.rb

def nav_link(*args, &block)
    if block_given?
      options      = args.first || {}
      html_options = args.second
      nav_link(capture(&block), options, html_options)
    else
      name         = args[0]
      options      = args[1] || {}
      html_options = args[2]

      html_options = convert_options_to_data_attributes(options, html_options)
      url = url_for(options)

      class_name = current_page?(url) ? 'active' : nil

      href = html_options['href']
      tag_options = tag_options(html_options)

      href_attr = "href=\"#{ERB::Util.html_escape(url)}\"" unless href
      "<li class=\"#{class_name}\"><a #{href_attr}#{tag_options}>#{ERB::Util.html_escape(name || url)}</a></li>".html_safe
    end
  end

Если вы посмотрите на приведенный выше код и сравните его с кодом link_to в url_helper.rb, единственная разница в том, что он проверяет, является ли url текущей страницей, и добавляет класс "active" к тегу wrapping li. Это связано с тем, что я использую помощник nav_link с Twitter Bootstrap навигационный компонент, который предпочитает ссылки, которые будут обернуты внутри тегов li, и применяется класс "active" к внешнему li.

Самое приятное в этом коде - это то, что он позволяет вам передать блок в функцию, как вы можете сделать с link_to.

Например, загрузочный навигационный список с значками будет выглядеть так:

Слим:

ul.nav.nav-list
  =nav_link root_path do
    i.icon-home
    |  Home
  =nav_link "#" do
    i.icon-user
    |  Users

Вывод:

<ul class="nav nav-list">
  <li class="active">
    <a href="/">
      <i class="icon-home"/>
      Home
    </a>
  </li>
  <li>
    <a href="#">
      <i class="icon-users"/>
      Users
    </a>
  </li>
</ul>

Кроме того, как и помощник link_to, вы можете передать HTML-параметры в nav_link, которые будут применены к тегу.

Пример передачи в заголовке якоря:

Слим:

ul.nav.nav-list
  =nav_link root_path, title:"Home" do
    i.icon-home
    |  Home
  =nav_link "#", title:"Users" do
    i.icon-user
    |  Users

Вывод:

<ul class="nav nav-list">
  <li class="active">
    <a href="/" title="Home">
      <i class="icon-home"/>
      Home
    </a>
  </li>
  <li>
    <a href="#" title="Users">
      <i class="icon-users"/>
      Users
    </a>
  </li>
</ul>

Ответ 14

Я использую простой помощник, подобный этому для ссылок верхнего уровня, поэтому страница /stories/my-story выделяет ссылку /stories

def nav_link text, url

  active = (url == request.fullpath || (url != '/' && request.fullpath[0..(url.size-1)] == url))

  "<li#{ active ? " class='selected'" : '' }><a href='#{url}'>#{text}</a></li>".html_safe

end

Ответ 15

Позвольте мне показать мое решение:

_header.html.erb

  <ul class="nav">
    <%= nav_tabs(@tabs) %> 
  </ul>

application_helper.rb

 def nav_tabs(tabs=[])
    html = []
    tabs.each do |tab| 
      html << (content_tag :li, :class => ("current-page" if request.fullpath.split(/[\??]/)[0] == tab[:path]) do
        link_to tab[:path] do
          content_tag(:i, '', :class => tab[:icon]) +
          tag(:br) +
          "#{tab[:name]}"
        end
      end)        
    end

    html.join.html_safe
  end

application_controller.rb

before_filter :set_navigation_tabs

private
def set_navigation_tabs
  @tabs = 
    if current_user && manager?
      [
        { :name => "Home", :icon => "icon-home", :path => home_index_path },
        { :name => "Portfolio", :icon => "icon-camera", :path => portfolio_home_index_path },
        { :name => "Contact", :icon => "icon-envelope-alt", :path => contact_home_index_path }
      ]
    elsif current_user && client?
      ...
    end

Ответ 16

Для меня лично я использовал комбинацию ответов здесь

<li class="<%= 'active' if current_page?(inventory_index_path) %>"><a href="#">Menu</a></li>

Я использую материализацию css, и мой способ сделать основные категории разборными - использовать код ниже

$('.active').closest(".collapsible.collapsible-accordion")
            .find(".collapsible-header")
            .click();

надеюсь, что это поможет кому-то

Ответ 17

В соответствии с ответом от Skilldrick я изменил его на следующее:

def nav_link(*args, &block)
  is_active = current_page?(args[0]) || current_page?(args[1])
  class_name = is_active ? 'active' : nil

  content_tag(:li, class: class_name) do
    link_to *args, &block
  end
end

чтобы сделать его намного более полезным.

Ответ 18

Эта версия основана на @Skilldrick one, но позволяет вам добавлять html-контент.

Таким образом, вы можете сделать:

nav_link "A Page", a_page_path

но также:

nav_link a_page_path do
  <strong>A Page</strong>
end

или любого другого содержимого html (вы можете добавить значок, например).

Здесь хелпер:

  def nav_link(name = nil, options = nil, html_options = nil, &block)
    html_options, options, name = options, name, block if block_given?
    options ||= {}

    html_options = convert_options_to_data_attributes(options, html_options)

    url = url_for(options)
    html_options['href'] ||= url

    class_name = current_page?(url) ? 'current' : ''
    content_tag(:li, :class => class_name) do  
      content_tag(:a, name || url, html_options, &block)
    end
  end

Ответ 19

все это работает с простыми навигационными барами, но как насчет выпадающего подменю? когда выбрано подменю, верхний пункт меню должен быть сделан "текущим", в этом случае tabs_on_rails me будет решением

Ответ 20

Вот как я решил в своем текущем проекте.

def class_if_current_page(current_page = {}, *my_class)
    if current_page?(current_page)
      my_class.each do |klass|
        "#{klass} "
      end
    end
  end

Тогда..

li = link_to company_path 
    class: %w{ class_if_current_page( { status: "pending" }, "active" ), "company" } do  
      Current Company

Ответ 21

Мой простой способ -

application.html.erb,

<div class="navbar">
    <div class="<%= @menu1_current %> first-item"><a href="/menu1"> MENU1 </a></div>
    <div class="<%= @menu2_current %>"><a href="/menu2"> MENU2 </a></div>
    <div class="<%= @menu3_current %>"><a href="/menu3"> MENU3 </a></div>
    <div class="<%= @menu4_current %> last-item"><a href="/menu4"> MENU4 </a></div>
</div>

main_controller.erb,

class MainController < ApplicationController
    def menu1
        @menu1_current = "current"
    end

    def menu2
        @menu2_current = "current"
    end

    def menu3
        @menu3_current = "current"
    end

    def menu4
        @menu4_current = "current"
    end
end

Спасибо.

Ответ 22

Если вы также хотите поддерживать хеш-параметры html-параметров в представлении. Например, если вы хотите называть его другим классом или id CSS, вы можете определить вспомогательную функцию следующим образом.

def nav_link_to(text, url, options = {})
  options[:class] ||= ""
  options[:class] += " active"
  options[:class].strip!
  link_to text, url, options
end

Итак, в представлении вызовите этот помощник так же, как вы назовете link_to helper

<%= nav_link_to "About", about_path, class: "my-css-class" %>

Ответ 23

Я думаю, что я придумал простое решение, которое может быть полезно для многих случаев использования. Это позволяет мне:

  • Поддержка не только обычного текста, но и HTML внутри link_to (например, добавить значок внутри ссылки)
  • Добавьте несколько строк кода в application_helper.rb
  • Добавить active ко всему имени класса элемента ссылки, а не быть единственным классом.

Итак, добавьте это в application_helper.rb:

def active_class?(class_name = nil, path)
  class_name ||= ""
  class_name += " active" if current_page?(path)
  class_name.strip!
  return class_name
end

И на вашем шаблоне вы можете иметь что-то вроде этого:

<div class="col-xs-3">
  <%= link_to root_path, :class => active_class?("btn btn-outline-primary", root_path) do %>
    <i class="fa fa-list-alt fa-fw"></i>
  <% end %>
</div>

В качестве бонуса вы можете указать или нет class_name и использовать его следующим образом: <div class="<%= current_page?(root_path) %>">

Благодаря предыдущим ответам 1, 2 и ресурсы.

Ответ 24

Создайте метод в ApplicationHelper, как показано ниже.

def active controllers, action_names = nil
  class_name = controllers.split(",").any? { |c| controller.controller_name == c.strip } ? "active" : ""
  if class_name.present? && action_names.present?
    return action_names.split(",").any? { |an| controller.action_name == an.strip } ? "active" : ""
  end
  class_name
end

Теперь используйте его в представлении, как показано ниже.

1. Для всех действий любого конкретного контроллера

<li class="<%= active('controller_name')%>">
....
</li>

2. Для всех действий многих контроллеров (с разделенной запятой)

<li class="<%= active('controller_name1,controller_name2')%>">
....
</li>

3. Для конкретного действия любого конкретного контроллера

<li class="<%= active('controller_name', 'action_name')%>">
....
</li>

4. Для конкретных действий многих контроллеров (с разделенной запятой)

<li class="<%= active('controller_name1,controller_name2', 'action_name')%>">
....
</li>

5. Для некоторых конкретных действий любого конкретного контроллера

<li class="<%= active('controller_name', 'index, show')%>">
....
</li>

6. Для некоторых конкретных действий многих контроллеров (с разделенной запятой)

<li class="<%= active('controller_name1,controller_name2', 'index, show')%>">
....
</li>

Надеюсь, что это поможет