rails应用包含许多不同的内容页面。页面被组织成小组,称为章节:
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
章节也需要组织,但最好的方法是什么 - 重用部分本身,或创建新的单元模型?
选项1 - 重复使用部分
允许Section有子节点和父节。这样,您不需要创建具有与Section类似的字段的另一个模型。有些部分会有很多页面,而其他部分则有很多子部分:
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
选项2 - 新单位模型
创建另一个名为Unit的模型来组织这些部分。它将有许多类似的字段,但它将是一个明显独立的实体。
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
选项1的优点是避免了一些重复,如果需要更多级别,可以在将来进行调整。但是,选项2清楚地区分了具有多个页面的章节的角色,其中包括具有多个章节的单元,这可以帮助保持其他代码清晰。哪种方法最好?
更新
似乎选项2会有更清晰的代码,例如在浏览所有章节时。是否值得重新使用Sections,如果它会使一些代码更复杂?例如,以下是如何以有条理的方式列出所有章节:
选项2 - 对于每个单元,列出所有子节。然后列出任何不在任何单位的部分。
选项1 - 对于每个父节,列出所有子节。然后列出任何没有父节或子节的节。
答案 0 :(得分:3)
如果你看到Section及其子节点中定义了完全相同的方法,那么值得重用Section(使用选项1)。否则,您应该选择选项2.
关于如何以有组织的方式列出所有章节的问题:
选项1 - 除非您想要遍历一个包含父节和子节的集合,否则不会这样做。看看我们如何在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)
选项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)
正如您所看到的,两个选项都有非常类似的代码用于列出子项和父项,因此在决定选择哪个选项时不应该关注。
答案 1 :(得分:2)
这实际上取决于你想走多远。如果它只是一个额外的层次结构,那么肯定会使用新模型。如果您希望能够深入2级以上,那么请务必选择重复使用部分。
答案 2 :(得分:0)
我会使用awesome_nested_set来使用嵌套的部分。通过这条路线,您可以减少获取节及其所有子节所需的数据库调用次数。除了组部分之外,Unit类没有做太多的工作,看起来它也复制了部分常用的列,例如标题...另外需要注意的是,如果您的要求包括具有任意深度嵌套部分的能力。使用单位方法,你会陷入1级深度。
答案 3 :(得分:0)
您不必为所有数据存储使用关系数据库。
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