【问题标题】:Design of Duplicative Nested Models in RailsRails 中重复嵌套模型的设计
【发布时间】:2018-08-14 22:12:32
【问题描述】:

我正在尝试为一所大学设计 Rails 5 应用程序。作为第一步,我尝试设计“部门”相关模型(一般单位),例如院系、职业学校、学院、本科课程、研究生课程等。但是我发现这个案例比我预期的要复杂一些。

以下是根据我的情况构建的真实数据结构:

University ->
  -> Academies
      -> Undergraduate Programs
      -> Divisions
          -> Undergraduate Programs
          -> Departments
  -> Vocational Schools
      -> Undergraduate Programs
      -> Divisions
          -> Undergraduate Programs
  -> Faculties
      -> Undergraduate Programs
      -> Departments
      -> Divisions
          -> Undergraduate Programs
          -> Departments

您可以将所有这些模型视为嵌套的 has_many 关系。例如,一所大学拥有许多院系。一个教员有_many部门和has_many部门。一个教师部门 has_many 部门等。理论上,每个级别的行为都像一个新的 has_many。

例如,看一下Faculty。部门可以直接隶属于学院,也可以隶属于部门。但是,无论它们位于何处,它们都是部门,并且它们的行为方式完全相同。换句话说,为位于 Faculty 下的 Department 和 Divisions 下的 Department 创建不同的模型对于我的情况来说是非常重复和无意义的。本科课程也可以这样说。我正在寻找更好的选择。

我一开始想到了多态,但我不确定它是否是解决这个问题的正确方法。问题是,解决此类问题的最佳方法是什么?

【问题讨论】:

  • 您是否需要某些模型(部门、部门、计划、学院、学校)的特定信息?还有其他未显示的不同模型吗?或者您可能想要一种灵活的方法并能够添加新类型的孩子。
  • 是的 Pablo,所有这些模型都将有它们的自定义方法和行为。正如你所说,未来可能还会有更多的子模型。

标签: ruby-on-rails ruby-on-rails-5


【解决方案1】:

多态是你最好的选择。每个学校,部门和部门都是一样的。他们有一个父母,他们有多个孩子,他们可能有多个学生和教师。根据您打算实现的业务逻辑类型,您可能只需按名称或类型对其进行分类,然后使用树来捕获结构即可。

class Department < ActiveRecord::Base
  belongs_to :parent, class_name: 'Department', optional: true
  has_many :children, class_name: 'Department'
  has_many :staff
  has_many :students
end

不过,与其自己管理所有这些,我建议您查看一个库来为您处理它。像Ancestery 这样的东西会是一个很好的起点。

我认为您的模型不需要很复杂。单个对象应该适用于 Schools、Divisions 和 Departments,除非它们每个都有独特的业务逻辑。即便如此,如果你给对象一个类型,你也许可以把那个业务逻辑放在他们自己的模型中。

【讨论】:

    【解决方案2】:

    您可以结合使用单表继承 (STI) 和多态:

    # in lack of a better name
    class UniversityUnit < ApplicationRecord
      belongs_to :university
    
      has_many :undergraduate_programs,
        as: :unit
    
      has_many :divisions, 
        as: :unit
    
      has_many :departments, 
        through: :divisions
    
      has_many :division_undergraduate_programs,
         through: :divisions
    end
    
    class Academy < UniversityUnit
    
    end
    
    class VocationalSchool < UniversityUnit
    
    end
    
    class Faculity < UniversityUnit
    
    end
    
    class Division
      belongs_to :unit, polymorphic: true 
      has_many :departments, as: :unit
    end
    
    class UndergraduateProgram
      belongs_to :unit, polymorphic: true 
      has_many :departments, as: :unit
    end
    
    class Department
      belongs_to :unit, polymorphic: true
    end
    

    最棘手的部分将是处理多态性和遍历图带来的连接/急切加载问题。

    或者使用多表继承,并将每个树节点声明为通用类型,但与特定类型有关联:

    class Organization < ApplicationRecord
      belongs_to :specific_type, polymorpic: true
      belongs_to :organization, optional: true
      has_many :children, class_name: 'Organization'
      has_many :grand_children, 
        through: :children,
        source: :children
    end
    
    class Academy < ApplicationRecord
      has_one :organization, as: :specific_type
    end
    
    class Department < ApplicationRecord
      has_one :organization, as: :specific_type
    end
    

    这就是 Drupal 在后端的工作方式。

    这种自连接关联可让您创建无限深度的树,而无需为每个级别增加额外的复杂性。在急切加载和连接关联记录时,您还可以避免很多多态性陷阱。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多