部分传递设计用户路径

Pass the devise user path in a partial

我正在尝试使用以下信息创建侧边栏菜单:

# app/controllers/users_controller.rb

def show
  @user = User.friendly.find(params[:id])
end
# config/routes.rb

get "/user/:id", to: "users#show"

我有 link 从下拉菜单到 current_user 路径:

<!-- app/views/layouts/_dropdown_menu.html.erb -->

<%= link_to "My Account", current_user %>

这是我创建侧边栏菜单的方式:

<!-- app/views/layouts/dashboard.html.erb -->

<%= render "shared/sidebar_panel" %>
<!-- app/views/shared/_sidebar_panel.html.erb -->

<%= render "shared/nav" %>
<!--  app/views/shared/_nav.html.erb -->

<% SidebarMenu.all.each do |entry| %>
  <% if entry[:group_title].present? %>
    <li class="nav-title"><%= entry[:group_title]%></li>
  <% end %>

  <%= render partial: 'shared/nav_submenu',
    collection: entry[:children],
    as: :sub_menu,
    locals: {parents: []} %>
<% end %>
<!-- app/views/shared/_nav_submenu.html.erb -->

<li>
  <a href="<%= sub_menu[:href] %>">
    <span><%= sub_menu[:title] %></span>
    <% if sub_menu[:subtitle].present? %>
      <span class="<%= sub_menu[:subtitle_class] %>">
        <%= sub_menu[:subtitle] %>
      </span>
    <% end %>
  </a>

  <% if sub_menu[:children].present? %>
    <ul>
      <%= render partial: 'shared/nav_submenu',
        collection: sub_menu[:children], 
        as: :sub_menu, 
        locals: {parents: parents + [sub_menu]} %>
    </ul>
  <% end %>
</li>

我有一个 SidebarMenu 模型并且我添加了 current_user 路径:

# app/models/sidebar_menu.rb

class SidebarMenu
  class << self
    include Rails.application.routes.url_helpers
  end

  def self.all
    [
      {   
        group_title: "Account & Contact",
        children: [
          {
            href: "#",
            title: "Account",
            icon: "...",
            children: [
              {
                href: current_user,
                title: "My Account"
              }
            ]
          },
          # ...
        ]
      }
    ]
  end
end

但它会引发一条错误消息:

undefined local variable or method `current_user' for SidebarMenu:Class

谁能告诉我如何解决这个问题?

这就是 Devise 设置 current_user 方法的方式:ActionView::Base 中的 current_user is a controller method included by devise and loaded in ActionController::Base class. It is also available in the views because it is a helper method which gets includedcurrent_user 不是 url 助手,它 returns 是一个 User 模型实例,link_to 可以自动变成 url。

current_user 超出了 SidebarMenu class 的范围。要修复它,只需将它作为参数传递:

class SidebarMenu
  def self.all user
    [{ href: user, title: "My Account" }]
  end
end

# in the view or controller
SidebarMenu.all(current_user) # => [{ href: #<User:0x0000563cc7c69198>, title: "My Account" }]

我认为,更好的方法是使用菜单 class 作为对象。它更灵活,更易于使用:

class Menu
  include Rails.application.routes.url_helpers

  def initialize(user:)
    @user = user
  end

  def user_menu
    {
      group_title: "Account",
      # NOTE: use url helper to return a path instead of a `User` model
      children: [{ href: user_path(user), title: "My Account" }]
    }
  end
  
  def sidebar_menu
    {
      group_title: "Main",
      children: [{ href: root_path, title: "Home" }]
    }
  end

  def all
    [sidebar_menu, user_menu]
  end

  private

    attr_reader :user
end

在视图中使用它:

Menu.new(user: current_user).user_menu[:children] 
# => [{ href: "/users/1", title: "My Account" }]

您还可以设置辅助方法:

# in the ApplicationController
private
  def menu
    @menu ||= Menu.new(user: current_user)
  end
  helper_method :menu

# in the view
menu.user_menu[:children] # => [{ href: "/users/1", title: "My Account" }]

# TODO: 
# menu.sidebar_menu
# menu.all.each do |group|
#   group[:group_title]
#   ...
# end

https://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to

https://api.rubyonrails.org/classes/AbstractController/Helpers/ClassMethods.html#method-i-helper_method

列出 url 个帮助者:Rails.application.routes.named_routes.helper_names

列出控制器助手:ApplicationController._helper_methods