Cara terbaik untuk menambahkan kelas "saat ini" ke navigasi di Rails 3

111

Saya memiliki beberapa halaman statis di menu navigasi. Saya ingin menambahkan kelas seperti "saat ini" ke item yang sedang ditampilkan.

Cara saya melakukannya adalah dengan menambahkan banyak metode pembantu (masing-masing untuk satu item) untuk memeriksa pengontrol dan tindakan.

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

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

Apakah ada cara yang lebih baik untuk melakukannya !? Cara saya saat ini sangat bodoh ...

PeterWong
sumber

Jawaban:

56

Bukan jawaban yang sebenarnya di sini, karena saya menggunakan cara yang sama seperti Anda. Saya baru saja menetapkan metode pembantu untuk menguji beberapa pengontrol atau tindakan:

Dalam application_helper.rb

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

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

Kemudian Anda dapat menggunakan if controller?("homepage") && action?("index", "show")di tampilan Anda atau metode pembantu lainnya…

Yannis
sumber
Cara Anda paling sesuai ketika ada beberapa halaman yang ditangani oleh pengontrol / tindakan yang berbeda tetapi dalam item menu yang sama, bukan? Apakah Anda menemukan lebih banyak keuntungan ~?
PeterWong
Tidak ada lagi keuntungan kecuali keringkasan sintaks. Saya ingin tahu apakah ada orang lain yang memiliki solusi yang lebih baik.
Yannis
Saya melakukan metode ini dengan sukses besar. Menambahkan kode ini ke tampilan: <% = link_to "Users", users_path, class: (controller? ("Users")? 'Selected': nil)%> Benar-benar rapi sehingga berfungsi untuk / users dan / users / new .
Andreas
1
sebuah perbaikan bisa terjadi controller_namedan mungkin action_namebukannya params
Francesco Belladonna
Sudah selesai dilakukan dengan baik. Saya tidak berpikir untuk membuat ini sederhana tetapi timbangan ini sangat bagus. +1
newdark-it
290

Saya membuat seorang pembantu menelepon 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

digunakan seperti:

nav_link 'Home', root_path

yang akan menghasilkan HTML seperti

<li class="current"><a href="/">Home</a></li>
Skilldrick
sumber
3
Ini berfungsi baik dengan twitter ootstrap jika Anda menggunakan navbar bootstrap twitter twitter.github.com/bootstrap/examples/hero.html
Lee McAlilly
41
Ubah ke class_name = current_page? (Link_path)? 'saat ini': nihil jika Anda tidak ingin tag kelas ditampilkan ketika tidak ada di halaman saat ini
Matthew Hui
1
Bagaimana Anda akan memodifikasi ini untuk daftar bersarang yang digunakan di dropdown?
doremi
9
KERING seperti gurun
Orlando
1
Saya telah menambahkan beberapa argumen tambahan extra_classes = nil, id = nil lalu di dalam content_tag content_tag (: li, class: [class_name, extra_classes], id: id) sehingga Anda dapat menambahkan kelas dan id Anda sendiri ke elemen juga :)
Jon
72

Gunakan current_page?helper untuk menentukan apakah Anda harus menetapkan "current"kelas atau tidak . Sebagai contoh:

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

Catatan Anda juga dapat melewati jalan (bukan hanya hash pilihan), misalnya: current_page?(root_path).

jpemberthy
sumber
3
Apakah ada cara untuk mendapatkan ini dengan mengabaikan parameter kueri?
Mohamad
@Mohamad, Anda dapat melakukan ini: current_page? (Controller: 'users', action: 'index')
nilid
26

Saya menggunakan fungsi nav_link (teks, tautan) ini di application_helper.rb (Rails 3) untuk menyelesaikan pekerjaan dan itu memutar tautan bar nav bootstrap twitter 2.0 saya untuk saya.

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

Contoh:

<%=nav_link("About Us", about_path) %>
Peyton
sumber
Ini dapat disederhanakan dengan menggunakan current_page?metode, seperti pada jawaban lain.
Teemu Leisti
10

Cara saya melakukannya adalah dengan menambahkan fungsi pembantu di application_helper

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

Kemudian di nav,

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

Ini menguji jalur link terhadap halaman saat ini uri dan mengembalikan kelas Anda saat ini atau string kosong.

Saya belum menguji ini secara menyeluruh dan saya sangat baru mengenal RoR (pindah setelah satu dekade dengan PHP) jadi jika ini memiliki kelemahan utama, saya ingin mendengarnya.

Setidaknya dengan cara ini Anda hanya membutuhkan 1 fungsi pembantu dan satu panggilan sederhana di setiap tautan.

sepenuhnya matang
sumber
1
Hanya masalah. Saya menggunakan request.path daripada request_uri (request_uri tidak berfungsi, mungkin masalah versi rails?). Jawaban Anda bersih dan elegan menurut saya.
Tony
6

Untuk membangun jawaban @Skilldrick ...

Jika Anda menambahkan kode ini ke application.js, itu akan memastikan bahwa setiap menu dropdown dengan anak-anak yang aktif juga akan ditandai sebagai aktif ...

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

Untuk merekap kode pendukung> Tambahkan pembantu yang disebut 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

digunakan seperti:

nav_link_to 'Home', root_path

yang akan menghasilkan HTML seperti

<li class="active"><a href="/">Home</a></li>
TheEricMiller
sumber
4

Saya pikir cara terbaik adalah

application_helper.rb:

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

Dan di menu:

<li class="<%= is_active('controller', 'action') %>">
IPIvliev
sumber
tidak apa-apa meninggalkan kelas "" kosong seperti itu?
Harsha MV
Iya. Mungkin terlihat aneh jika Anda melihat sumber melihat sekumpulan atribut kelas kosong, tetapi itu adalah HTML yang valid.
kobaltz
Anda dapat menggunakan <%= content_tag(:li, "Click me", class: is_active('controller', 'action')) %>, itu tidak akan mencetak atribut kelas untuk nil. apidock.com/rails/ActionView/Helpers/TagHelper/content_tag
neonmate
4

Saya tahu ini adalah jawaban yang sudah ketinggalan zaman , tetapi Anda dapat dengan mudah mengabaikan semua pemeriksaan halaman saat ini dengan menggunakan pembungkus link_to helper, yang disebut permata active_link_to , berfungsi persis seperti yang Anda inginkan, tambahkan kelas aktif ke tautan halaman saat ini

fuyi
sumber
4

Berikut adalah contoh lengkapnya, tentang cara menambahkan kelas aktif pada halaman menu bootstrap dalam tampilan rel.

    <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>
Little Phild
sumber
3

Saya menggunakan permata mengagumkan yang disebut Tabs on Rails .

es krim
sumber
1
Terima kasih untuk sarannya. Karena navigasi saya sangat sederhana dan hanya ada satu dengan item kecil, permata itu mungkin akan terlalu bertenaga.
PeterWong
3

Saya memiliki versi nav_link yang lebih ringkas yang bekerja persis seperti link_to, tetapi disesuaikan untuk mengeluarkan tag li pembungkus.

Letakkan baris berikut di application_helper.rb Anda

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

Jika Anda melihat kode di atas dan membandingkannya dengan kode link_to di url_helper.rb, satu-satunya perbedaan adalah ia memeriksa apakah url adalah halaman saat ini, dan menambahkan kelas "aktif" ke tag li pembungkus. Ini karena saya menggunakan pembantu nav_link dengan komponen nav Twitter Bootstrap yang lebih memilih tautan untuk dibungkus di dalam tag li dan kelas "aktif" diterapkan ke li luar.

Hal yang menyenangkan tentang kode di atas adalah memungkinkan Anda memasukkan blok ke dalam fungsi, seperti yang dapat Anda lakukan dengan link_to.

Misalnya, daftar navigasi bootstrap dengan ikon akan terlihat seperti ini:

Ramping:

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

Keluaran:

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

Selain itu, seperti helper link_to, Anda dapat memasukkan opsi HTML ke nav_link, yang akan diterapkan ke tag.

Contoh penyampaian judul untuk jangkar:

Ramping:

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

Keluaran:

<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>
Joe Chen
sumber
Mengagumkan. Bagi saya ini adalah opsi yang paling tepat karena memungkinkan blok. Terima kasih banyak!
Kasperi
3

Bagi saya pribadi, saya menggunakan kombinasi jawaban di sini

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

Saya menggunakan materialize css dan cara saya membuat kategori utama dilipat adalah dengan menggunakan kode di bawah ini

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

semoga bisa membantu seseorang

Petros Kyriakou
sumber
lupakan tentang ini. Terima kasih telah memposting ini sebagai pengingat.
newdark-it
2

The current_page?Metode tidak cukup fleksibel untuk saya (mengatakan Anda mengatur controller tapi tidak tindakan, maka hanya akan kembali benar pada tindakan indeks controller), jadi saya sudah membuat ini berdasarkan jawaban yang lain:

  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

Contoh:

nav_link_to "Pages", pages_url, :controller => 'pages'
ketidakrelatifan
sumber
Terima kasih atas jawaban Anda. Saya pikir jawaban Anda mirip dengan jawaban yang diterima sebenarnya :)
PeterWong
Saya menemukan jawaban ini melalui Google karena saya mengalami masalah ini, jadi saya pikir saya akan membantu semua orang yang menemukan ini juga :)
unrelativitas
2

Ya! Lihat artikel ini: Cara yang Lebih Baik untuk Menambahkan Kelas 'terpilih' ke Tautan di Rails

Letakkan nav_link_helper.rb ke dalam app / helpers dan itu bisa semudah:

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

Helper nav_link bekerja seperti pembantu link_to Rails standar, tetapi menambahkan kelas 'terpilih' ke tautan Anda (atau pembungkusnya) jika kriteria tertentu terpenuhi. Secara default, jika url tujuan tautan adalah url yang sama dengan url laman saat ini, kelas default 'dipilih' ditambahkan ke tautan.

Ada intinya di sini: https://gist.github.com/3279194

UPDATE: Sekarang ini adalah permata: http://rubygems.org/gems/nav_link_to

Dan Tello
sumber
Ini bagus. Saya mulai menggunakannya, dan menambahkan modifikasi untuk mendukung pemberian nama kelas ke elemen yang tidak dipilih, juga, sebagai komentar di intinya.
Teemu Leisti
2

Saya menggunakan penolong sederhana seperti ini untuk tautan tingkat atas sehingga /stories/my-storyhalaman menyoroti /storiestautan tersebut

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
sombong
sumber
2

Izinkan saya menunjukkan solusi saya:

_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
Mike Andrianov
sumber
1

Menurut jawaban dari Skilldrick , saya akan mengubahnya menjadi yang berikut:

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

agar lebih bermanfaat.

Tom Chen
sumber
1

Versi ini didasarkan pada versi @ Skilldrick tetapi memungkinkan Anda untuk menambahkan konten html.

Dengan demikian, Anda dapat melakukan:

nav_link "A Page", a_page_path

tetapi juga:

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

atau konten html lainnya (Anda dapat menambahkan ikon misalnya).

Di sini penolongnya adalah:

  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
Benjamin J. Benoudis
sumber
1

Saya rasa saya menemukan solusi sederhana yang mungkin berguna untuk banyak kasus penggunaan. Ini memungkinkan saya:

  • Mendukung tidak hanya teks biasa tetapi HTML di dalamnya link_to(misalnya menambahkan ikon di dalam tautan)
  • Tambahkan hanya beberapa baris kode ke application_helper.rb
  • Tambahkan activeke seluruh nama kelas dari elemen tautan alih-alih menjadi satu-satunya kelas.

Jadi, tambahkan ini ke 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

Dan pada template Anda, Anda dapat memiliki sesuatu seperti ini:

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

Sebagai bonus, Anda dapat menentukan atau tidak class_namedan menggunakannya seperti ini:<div class="<%= current_page?(root_path) %>">

Berkat jawaban sebelumnya 1 , 2 , dan sumber daya .

Juan Diego Gonzales
sumber
0

semua ini bekerja dengan bilah navigasi sederhana, tetapi bagaimana dengan sub-menu tarik-turun? ketika sub-menu dipilih, item menu teratas harus dibuat 'terkini' dalam hal ini tab_on_rails saya menjadi solusinya


sumber
0

Ini adalah bagaimana saya menyelesaikan proyek saya saat ini.

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

Kemudian..

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

Cara saya yang mudah -

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

Terima kasih.

Lwin Htoo Ko
sumber
0

Jika Anda juga ingin mendukung hash opsi html dalam tampilan. Misalnya jika Anda ingin memanggilnya dengan id atau kelas CSS lain, Anda dapat menentukan fungsi helper seperti ini.

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

Jadi dalam tampilan, panggil helper ini dengan cara yang sama seperti Anda memanggil link_to helper

<%= nav_link_to "About", about_path, class: "my-css-class" %>
Ken Hibino
sumber
0

Buat metode ApplicationHelperseperti di bawah ini.

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

Sekarang gunakan dalam tampilan seperti kasus penggunaan di bawah ini.

1. Untuk semua tindakan pengontrol tertentu

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

2. Untuk semua tindakan banyak pengontrol (dengan dipisahkan koma)

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

3. Untuk tindakan spesifik dari setiap pengontrol tertentu

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

4. Untuk tindakan spesifik dari banyak pengontrol (dengan dipisahkan koma)

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

5. Untuk beberapa tindakan khusus dari setiap pengontrol tertentu

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

6. Untuk beberapa tindakan tertentu dari banyak pengontrol (dengan dipisahkan koma)

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

Semoga membantu

Lalit Kumar Maurya
sumber