rails 6 中的多个下拉菜单
Multiple dropdown menus in rails 6
对 rails 很陌生,不知道如何构建动态菜单栏。
数据库使用简单的方法存储菜单项:
id | title | url | parent | position
--------------------------------------------------------------------
1 Books /books 0 1 (first link on menu bar)
2 Fiction /books/fiction 1 1 (first link under Books menu)
3 CDs /cd 0 2 (second link on menu bar)
4 Fantasy /books/fantasy 1
5 Singles /cd/single 2
6 Albums /cd/album 2
我需要获取此 table 中的所有条目并根据其父级显示它们。
父级为 0 的所有项目都将显示在菜单栏上。
当用户将鼠标悬停在任何父元素上时,其所有子元素都会列在其下方。
当我在 PHP 中执行此操作时,我使用了一个导致许多数据库调用的循环;一个是按位置顺序获取所有父项(因为管理员可以更改父项在菜单上出现的顺序),然后一个是每个父项获取其所有子元素(也是按位置顺序)。
然后我将每个结果项添加到一个以 parent_id 命名的数组中,最后连接数组。
$item[$parent][] = '
我知道 SQL 效率低下(PHP 可能也是如此),但这在当时并不重要。现在可以了。
知道如何在 ruby 中高效地工作吗?
我们假设存储此菜单信息的数据库table 称为nav_items。然后 Rails 约定将有一个名为 NavItem:
的模型
# app/models/nav_item.rb
class NavItem < ApplicationRecord
has_many :child_menu_items, class_name: NavItem, inverse_of: :parent_menu_item, foreign_key: :parent
belongs_to :parent_menu_item, class_name: NavItem, foreign_key: :parent, inverse_of: :child_menu_items
scope :top_level, { where("parent = ?", 0) }
end
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :populate_nav_vars
private
def populate_nav_vars
@nav_items = NavItem.top_level
end
end
# app/view/layouts/_nav.html
# @nav_items is defined in the controller as NavItem.top_level
# the nav structure is shown here as nested <ul> lists
# it can be rendered appropriately with css (e.g. Bootstrap)
<ul>
<%- @nav_items.each do |top_level_item| %>
<li><%= top_level_item.title %></li>
<li>
<ul>
<%- top_level_item.child_menu_items.each do |child_item| %>
<li><%= child_item.title %>
<%- end %>
</ul>
</li>
<%- end %>
</ul>
你真的不应该担心性能,它根本不应该引人注意。我在这里假设您想要每个页面上的导航菜单,因此填充所需变量的方便位置是 ApplicationController
并在 before_action 回调中填充变量。
如果性能问题与您有关,那么您应该将导航页面元素设为部分视图,并对部分应用 rails 缓存。
对 rails 很陌生,不知道如何构建动态菜单栏。 数据库使用简单的方法存储菜单项:
id | title | url | parent | position
--------------------------------------------------------------------
1 Books /books 0 1 (first link on menu bar)
2 Fiction /books/fiction 1 1 (first link under Books menu)
3 CDs /cd 0 2 (second link on menu bar)
4 Fantasy /books/fantasy 1
5 Singles /cd/single 2
6 Albums /cd/album 2
我需要获取此 table 中的所有条目并根据其父级显示它们。 父级为 0 的所有项目都将显示在菜单栏上。 当用户将鼠标悬停在任何父元素上时,其所有子元素都会列在其下方。
当我在 PHP 中执行此操作时,我使用了一个导致许多数据库调用的循环;一个是按位置顺序获取所有父项(因为管理员可以更改父项在菜单上出现的顺序),然后一个是每个父项获取其所有子元素(也是按位置顺序)。 然后我将每个结果项添加到一个以 parent_id 命名的数组中,最后连接数组。
$item[$parent][] = '
我知道 SQL 效率低下(PHP 可能也是如此),但这在当时并不重要。现在可以了。 知道如何在 ruby 中高效地工作吗?
我们假设存储此菜单信息的数据库table 称为nav_items。然后 Rails 约定将有一个名为 NavItem:
的模型# app/models/nav_item.rb
class NavItem < ApplicationRecord
has_many :child_menu_items, class_name: NavItem, inverse_of: :parent_menu_item, foreign_key: :parent
belongs_to :parent_menu_item, class_name: NavItem, foreign_key: :parent, inverse_of: :child_menu_items
scope :top_level, { where("parent = ?", 0) }
end
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :populate_nav_vars
private
def populate_nav_vars
@nav_items = NavItem.top_level
end
end
# app/view/layouts/_nav.html
# @nav_items is defined in the controller as NavItem.top_level
# the nav structure is shown here as nested <ul> lists
# it can be rendered appropriately with css (e.g. Bootstrap)
<ul>
<%- @nav_items.each do |top_level_item| %>
<li><%= top_level_item.title %></li>
<li>
<ul>
<%- top_level_item.child_menu_items.each do |child_item| %>
<li><%= child_item.title %>
<%- end %>
</ul>
</li>
<%- end %>
</ul>
你真的不应该担心性能,它根本不应该引人注意。我在这里假设您想要每个页面上的导航菜单,因此填充所需变量的方便位置是 ApplicationController
并在 before_action 回调中填充变量。
如果性能问题与您有关,那么您应该将导航页面元素设为部分视图,并对部分应用 rails 缓存。