Rails:类别、子类别和律师之间的关联

Rails: Association between Category, Subcategory, and Lawyer

我有大量的律师、类别和子类别列表。

提示(如果我的联想没问题,你可能会有线索)

  1. 在类别 Table 上,我不想看到类别 Table 上的列引用子类别。
  2. 在子类别 Table 上,我不想在子类别 Table 上看到引用类别的列。
  3. 并非所有类别都有子类别。即有些没有如图所示的子类别。
  4. 我有 2 个单独的表单来创建类别和子类别。
  5. 我将 category_id 和 subcategory_id 添加为我的律师 table 的外键。这样我就可以在创建时从律师表格中选择律师所属的类别或子类别。
  6. 另请注意:可以随时为没有子类别的类别以及已有子类别的类别下的新子类别以及律师创建子类别将放在它们下面。
  7. 这张图片是我现在的index/homepage的复制品,至少在上面的第6条任何时候任何时间生效之前,我希望使用循环来实现这个视图。

对我正在尝试做的事情的图示理解:

这是我的 3 个模型之间的关系

class Lawyer < ActiveRecord::Base
  belongs_to :category
  belongs_to :subcategory
end

class Category < ActiveRecord::Base
  has_many :lawyers
end

class Subcategory < ActiveRecord::Base
  #belongs_to :category #Do I want "category_id" in Subcategories Table?
  has_many :lawyers
end

问题

Is my association on those 3 models okay for the Hint I gave? This is pretty confusing.

您不需要 Subcategory model/table,特别是如果它们具有相同的列。您的 categories table 应该有一个 parent_id 列。当一个类别具有指向另一个类别记录的 parent_id 值时,它就是一个子类别。 NULL parent_id 的类别是顶级类别。

例子

class Lawyer < ActiveRecord::Base
  belongs_to :category
end

class Category < ActiveRecord::Base
  has_many :lawyers

  # This is called a self referential relation. This is where records in a 
  # table may point to other records in the same table.
  has_many :sub_categories, class_name: "Category", foreign_key: :parent_id

  # This is a scope to load the top level categories and eager-load their 
  # lawyers, subcategories, and the subcategories' lawyers too.
  scope :top_level, -> { where(parent_id: nil).include :lawyers, sub_categories: :lawyers }
end

注意:您应该创建迁移以将 parent_id 列添加到类别 table。您可以删除子类别 table.

现在创建一些类别(我假设有一个 name 列):

cat = Category.create name: "Corporate and Commercial Law"
subcat = Category.new name: "Corporate Tax", parent_id: cat.id
subcat.lawyers << Lawyer.find_by_name("Sabina Mexis")
subcat.save

内容示例table:

<% Category.top_level.each do |cat| %>
  <%= cat.name %>
  <% cat.sub_categories.each do |subcat| %>
    <%= subcat.name %>
    <%= subcat.lawyers.each do |laywer| %> 
      <%= lawyer.name %>
    <% end %>
  <% end %>
<% end %>

以上是一个简化的例子。希望对您有所帮助。

更新

要增强您的表单以允许您创建子类别并分配其父类别,请使用 select 菜单,其中包含 top_level 个类别 ID:

<%= form_for Category.new do |f| %>
  <%= f.text_field :name %>
  <%= f.select :parent_id, options_from_collection_for_select(Category.top_level, :id, :name) %>
  <%= f.submit %>
<% end %>

如果不熟悉,请查看 options_from_collection_for_select 的文档。它所做的是构建一个 select 菜单,其中类别 :id 作为值,它们的 :name 作为菜单中的文本。确保将 :parent_id 添加到强参数中,以允许通过 params[:category].

进行批量分配

laywer 错误只是我示例代码中的错字,现在已修复。