简体   繁体   English

如何在Ruby on Rails中构建多层层次结构?

[英]How to Structure Multiple Levels of Hierarchy in Ruby on Rails?

A rails app contains many different Pages of content. Rails应用程序包含许多不同的内容页面。 The Pages are organized into small groups known as Sections: 这些页面被组织为称为“小节”的小组:

class Page < ActiveRecord::Base
   attr_accessible: section_id #etc..
   belongs_to :section
end

class Section < ActiveRecord::Base
  attr_accessible :title #, etc... 
  has_many :pages
end

The Sections need to be organized too, but what is the best way to do this - re-use sections themselves, or create a new Unit model? 部门也需要组织起来,但是最好的方法是这样做-重用部门本身,还是创建新的单元模型?

Option 1 - Re-use Section 选项1-重用部分
Allow Section to have children and parent Sections. 允许科具有子级和父级。 That way, you don't need to create another model with similar fields as Section. 这样,您无需创建具有与Section相似字段的其他模型。 Some sections will have_many pages, and other sections will have_many children sections: 一些部分将具有多个页面,而其他部分将具有多个子区域:

class Section < ActiveRecord::Base
  attr_accessible :parent_id  :title # etc... 
  has_many :pages

  belongs_to :parent, class_name: "Section"
  has_many :children, class_name: "Section", foreign_key: "parent_id"
end

Option 2 - new Unit model 选项2-新的单位模型
Create another model called Unit to organize the sections. 创建另一个名为Unit的模型来组织各部分。 It will have many similar fields to section, but it will be a clearly separate entity. 该节将有许多类似的字段,但是它将是一个明显独立的实体。

class Section < ActiveRecord::Base
  attr_accessible :title, :unit_id # etc... 
  has_many :pages
  belongs_to :units
end

class Unit < ActiveRecord::Base
  attr_accessible :title # etc... 
  has_many :sections
end

The advantage of Option 1 is it avoid some duplication, and could be adapted in the future if even more levels are needed. 选项1的优点是它避免了重复,并且如果需要更多级别,可以在将来进行调整。 However, Option 2 clearly separates the roles of Sections, which have_many pages, from Units, which have_many Sections, which can help keep other code clear. 但是,选项2明确区分了具有have_many页的Sections和具有Have_many Sections的Units的角色,这可以帮助保持其他代码的清晰。 Which is the best approach? 哪种方法最好?

Update 更新资料
It seems Option 2 would have clearer code, such as when going through all the Sections. 似乎选项2会有更清晰的代码,例如遍历所有部分时。 Is it worth re-using Sections if it would make some code more complicated? 如果会使某些代码更复杂,是否值得重用Sections? For example, here's how to list all the Sections in an organized manner: 例如,以下是如何以有组织的方式列出所有版块的方法:

Option 2 - For each Unit, list all the child sections. 选项2-对于每个单元,列出所有子部分。 Then list any Sections that aren't in any Unit. 然后列出任何不在任何单元中的部分。

Option 1 - For each parent Section, list all the children Sections. 选项1-对于每个父节,列出所有子节。 Then list any Section that has with no parent Section or child Section. 然后列出没有父节或子节的任何节。

It will be worth reusing Section(using Option 1), if you see Section and its children having exactly the same methods defined in them. 如果您看到Section和它的子级在它们中定义的方法完全相同,则值得重用Section(使用选项1)。 Otherwise, you should go for Option 2. 否则,您应该选择选项2。

Regarding the concerns you had on how to list all the Sections in an organized manner: 关于您对如何以有组织的方式列出所有部分的关注:

Option 1 - This isn't and can be done unless you want to iterate through one collection which has the parent section and the children sections. 选项1-除非您要遍历具有父部分和子部分的一个集合,否则不能这样做。 See how we could do some of the queries in ActiveRecord below: 在下面的ActiveRecord中查看如何执行某些查询:

sections_with_parent = Section.joins(:parent)
sections_with_children = Section.joins(:children).uniq
parent_key_with_children_values = Section.joins(:children).uniq.inject({}) do |result, section|
  result.merge({section => section.children})
end
sections_with_no_parent = Section.where(parent_id: nil)

Option 2 - Below are some code for comparison with above: 选项2-以下是与上面进行比较的一些代码:

sections_with_parent = Section.joins(:unit)
units_with_children = Unit.joins(:sections).uniq
parent_key_with_children_values = Unit.joins(:sections).uniq.inject({}) do |result, unit|
  result.merge({unit => unit.sections })
end
sections_with_no_parent = Section.where(unit_id: nil)

As you can see, both options will have very similar code for listing children and parents so that shouldn't be a concern when deciding on what option to go for. 如您所见,这两个选项将具有非常相似的代码来列出孩子和父母,因此在决定选择哪个选项时不必担心。

It really depends on how far you want to go. 这实际上取决于您要走多远。 If it's just one extra level of hierarchy, then definitely go with the new model. 如果这只是层次结构的另一层,那么肯定要使用新模型。 If you're looking to be able to go 2+ levels deep, definitely go with the option of reusing sections. 如果您希望能够深入2个以上级别,则可以选择重用部分。

I would go with the nested set of sections using awesome_nested_set . 我会使用awesome_nested_set来嵌套部分。 By going this route you reduce the number of database calls needed to get a section and all of its child sections. 通过这种方法,您减少了获得一个节及其所有子节所需的数据库调用次数。 The Unit class doesn't do much other than group sections and seems like it also duplicates columns common to section eg title... Another thing to note is if your requirements include the ability to have arbitrarily deep nested sections. Unit类除了分组部分外没有做太多其他事情,并且似乎也复制了该部分共有的列,例如title ...要注意的另一件事是,如果您的要求包括具有任意深度嵌套部分的能力。 With the Unit approach you're stuck at 1 level deep. 使用单元方法时,您只能停留在1级深度。

You don't have to use a relational database for all of your data storage. 您不必将关系数据库用于所有数据存储。

Mongodb (mongoid: http://mongoid.org/en/mongoid/index.html ) may be a good solution to your problem. Mongodb(mongoid: http ://mongoid.org/en/mongoid/index.html)可能是解决您的问题的好方法。

class Page
  include Mongoid::Document

  embeds_many :sections, :class_name => 'Sections', :inverse_of => :page
end

class Section
  include Mongoid::Document
  field :title, :type => String, :default => ''

  embedded_in :page, :class_name => 'Page', :inverse_of => :sections
end

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM