Rails 7+Stimulus:动态隐藏无数据的子子分类下拉菜单
问题:三级分类联动下拉菜单按需显示子子分类
我实现了分类/子分类/子子分类三级联动下拉菜单,整体功能正常,但存在一处问题:部分子分类没有对应的子子分类,我希望隐藏最后一个子子分类下拉菜单,仅当用户选择的子分类存在子子分类时才显示它。恳请提供解决方案。
现有代码
数据库表结构(categories)
create_table :categories do |t| t.string "name", limit: 255 t.text "description", limit: 65535 t.integer "parent_id", limit: 4 t.boolean "important", default: false t.integer "position", limit: 4, default: 0 t.timestamps end
Category 模型(category.rb)
class Category < ApplicationRecord validates :name, presence: true has_many :jobs belongs_to :parent, foreign_key: :parent_id, class_name: 'Category' , :optional => true has_many :subcategories, foreign_key: :parent_id, class_name: 'Category' has_many :subsubcategories, foreign_key: :parent_id, class_name: 'Category' end
Job 模型(job.rb)
class Job < ApplicationRecord validates :title,:category_id, :description, presence: true validates :category, :presence => true belongs_to :user belongs_to :category , -> { order("name") } belongs_to :subcategories, class_name: "Category" belongs_to :subsubcategories, class_name: "Category" end
Stimulus 控制器(dropdown_controller.js)
import { Controller } from "@hotwired/stimulus"; // connect to data-controller="dropdown" export default class extends Controller { submit () { this.element.requestSubmit(); } }
Jobs 控制器(jobs_controller.rb)
class JobsController < ApplicationController before_action :authenticate_user!, except: [:index, :show] before_action :set_categories def index @jobs = Job.all end def new @category = Category.find_by(id: params[:category]) @categories = Category.where(parent_id: nil) @subcategories = @category.subcategories if @category @subsubcategories = Category.where(:parent_id => params[:subcategories]) @job = Job.new end def create @job = Job.new(job_params.merge({ user: current_user })) if @job.save format.html { redirect_to root_path, notice: "Job was successfully created." } else render :new, status: :unprocessable_entity end end private def job_params params.require(:job).permit(:title, :description,:category_id).merge(user: current_user) end def set_categories @category = Category.find_by(id: params[:category].presence) @subcategory = Category.find_by(id: params[:subcategories]) @subsubcategory = Category.find_by(id: params[:subsubcategories]) end end
视图文件(views/jobs/new.html.erb)
<%= turbo_frame_tag "form" do %> <%= form_tag new_job_path, method: :get, data: { controller: "dropdown", action: "change->dropdown#submit" } do %> <%= select_tag :category, options_from_collection_for_select(@categories, "id", "name", @category&.id ), prompt: "Select a category" %> <%= select_tag :subcategories, options_from_collection_for_select(@subcategories || [], "id" , "name", @subcategory&.id), prompt: "Select a subcategories category" %> <%= select_tag :subsubcategories, options_from_collection_for_select(@subsubcategories || [], "id" , "name", @subsubcategory&.id), prompt: "Select a subsubcategories category" %> <% end %> <% end %>
解决方案
1. 控制器层:添加子子分类存在性判断
修改 jobs_controller.rb 的 new 方法,新增变量判断选中的子分类是否有子子分类,仅存在时加载数据:
def new @category = Category.find_by(id: params[:category]) @categories = Category.where(parent_id: nil) @subcategories = @category.subcategories if @category # 获取当前选中的子分类 @selected_subcategory = Category.find_by(id: params[:subcategories]) # 标记是否存在子子分类 @has_subsubcategories = @selected_subcategory&.subsubcategories&.exists? # 仅当存在时加载子子分类数据 @subsubcategories = @selected_subcategory.subsubcategories if @has_subsubcategories @job = Job.new end
2. 视图层:条件渲染子子分类下拉框
修改 views/jobs/new.html.erb,只有在 @has_subsubcategories 为真时才显示最后一个下拉框:
<%= turbo_frame_tag "form" do %> <%= form_tag new_job_path, method: :get, data: { controller: "dropdown", action: "change->dropdown#submit" } do %> <%= select_tag :category, options_from_collection_for_select(@categories, "id", "name", @category&.id ), prompt: "选择分类" %> <%= select_tag :subcategories, options_from_collection_for_select(@subcategories || [], "id" , "name", @subcategory&.id), prompt: "选择子分类" %> <%# 仅当前子分类有子子分类时显示 %> <% if @has_subsubcategories %> <%= select_tag :subsubcategories, options_from_collection_for_select(@subsubcategories || [], "id" , "name", @subsubcategory&.id), prompt: "选择子子分类" %> <% end %> <% end %> <% end %>
可选优化:简化模型关联
Category 模型中 subcategories 和 subsubcategories 逻辑重复,可以合并为通用关联,方便后续层级扩展:
class Category < ApplicationRecord validates :name, presence: true has_many :jobs belongs_to :parent, foreign_key: :parent_id, class_name: 'Category', optional: true # 通用子分类关联 has_many :children, foreign_key: :parent_id, class_name: 'Category' # 保留原有别名兼容现有代码 has_many :subcategories, class_name: 'Category', foreign_key: :parent_id has_many :subsubcategories, through: :subcategories, source: :children end
内容的提问来源于stack exchange,提问作者ukeagle
相关产品推荐
相关产品推荐

