rails类别作为自引用模型

时间:2017-06-02 08:25:25

标签: ruby-on-rails

我有一个类别模型,'用例是topcategory,category或subcategory。

class Category < ApplicationRecord
  has_many :subcategories, class_name: "Category", foreign_key: "parent_id"
  belongs_to :topcategory, class_name: "Category"

  has_many :skills
end

class Skill < ApplicationRecord
  belongs_to :category
end

1)如何按照此处提到的collection_check_boxes列出每个类别(层次结构化)相关技能:https://stackoverflow.com/a/44282875/8090895

2)我需要在分层列表中列出这些类别,例如

topcategory1
-Skill1, Skill2, Skill6
-category1
--Skill3, Skill4
--Subcategory1
---Skill7, Skill8
--Subcategory2
---Skill5
-category2
topcategory2
...

我怎么能这样做?

我目前的类别控制器设置是:

@all_categories = Category.includes(:subcategories, :skills)
@topcategories = @all_categories.where("parent_id IS NULL")
@categories = @all_categories.where("parent_id IS NOT NULL")

3)为了创造新技能,我需要一个包含所有类别的结构化列表的下拉列表。我发现只有使用options_from_collection_for_select的可能性,但在这里我不能自己选择“maingroups”。在我的用例中,我甚至需要所有树实例都可以选择。

我感谢任何帮助。提前感谢您的提示和帮助。如果您需要更多信息,请选择它。

第3部分的Edit1):另一个想法是填写下拉列表,如下所示:

Topcategory1//
Topcategory1//Category1//
Topcategory1//Category1//Subcategory1
Topcategory1//Category1//Subcategory2
Topcategory2//
Topcategory2//Category2//
Topcategory2//Category2//Subcategory3
...

这将是/应该是正常列表,这使得可以选择任何类别元素。顶级和类别多次显示的事实对我来说没问题。我只是不知道,我怎么能填写这样的下拉列表。

1 个答案:

答案 0 :(得分:0)

首先为类别创建自加入关联:

class Category < ApplicationRecord
  belongs_to :parent, class_name: 'Category',
                      optional: true
  has_many :children, class_name: 'Category', 
                      foreign_key: 'category_id'
end

这允许您根据需要无限地嵌套类别,并将记录保存在单个表中。如果您需要重新组织分类,这一点至关重要。

然后,您可以设置技能和类别之间的关联:

class Skill < ApplicationRecord
  belongs_to :category
end

要加入子类别的类别和技能,您可以这样做:

@categories = Category.left_joins(:skills, children: [:skills])
@top_level = @categories.select { |c| c.parent.nil? }
  

3)为了创造新技能,我需要一个带结构化列表的下拉列表   所有类别。我发现只有使用的可能性   options_from_collection_for_select但在这里我无法选择   &#34; maingroups&#34;他们自己。在我的用例中,我甚至需要所有的树   实例可以选择。

不幸的是,HTML规范不允许嵌套的<optgroup>元素。您可以通过缩进选项来伪造嵌套。还有一些javascript选项,如Select2,可以使它更有用。

&#13;
&#13;
<select name="person[skill_ids]" multiple="true">
  <optgroup label="Programming">
    <option value="1">GIT</option>
  </optgroup> 
  <optgroup label="&nbsp;&nbsp;Programming Languages" class="level-2">
    <option value="2">&nbsp;&nbsp;Ruby</option>
    <option value="2">&nbsp;&nbsp;Python</option>
  </optgroup>
</select>
&#13;
&#13;
&#13;

使用rails分组集合帮助程序可能不适合您的用例。因此,您可能需要手动创建选项:

<select name="person[skill_ids]">
  <%= @top_level.each do |tc| %>
    <optgroup label="<%= tc.name %>" class="parent-category">
      <%= options_for_select(tc.skills.map { |s| [s.name, s.id] })
    </optgroup>
    <%= tc.children.each do |subcategory| %>
      <optgroup label="&nbsp;&nbsp;<%= subcategory.name %>" class="subcategory">
        <%= options_for_select(subcategory.skills.map { |s| ["&nbsp;&nbsp;#{s.name}", s.id] }) %>
      </optgroup>
    <% end %>
  </optgroup>
  <% end %>
</select>

在这里,您还将检查表单对象是否具有该技能,并将所选属性应用于<option>