【问题标题】:RubyOnRails / building full tree from deeply nested relational modelsRubyOnRails / 从深度嵌套的关系模型构建完整的树
【发布时间】:2018-08-01 00:33:15
【问题描述】:

具有以下自相关多对多设置:

class Item < ApplicationRecord
  has_many :joins, dependent: :destroy
  has_many :child_items, through: :joins
end

class Join < ApplicationRecord
  belongs_to :item
  belongs_to :child_item, class_name: 'Item'
end

重建完整树的 json 表示最直接的模式是什么?喜欢:

[
  {
    id: 1,
    child_items: [
      {
        id: 2,
        child_items: [
          {
            id: 3,
            child_items: etc… untils there are no more
          }
        ]
    ]
  }, {
    id: 4,
    child_items: { etc... }
  }, etc…
]

到目前为止,我有以下简单内容:

def render
  iterate(entrypoint_item)
end

def iterate(node)
  h = JSON.parse(node.to_json)
  h['child_items'] = []
  node.child_items.collect{ |child|
    h['child_items'] << iterate(child)
  }
  h.delete('child_items') if h['child_items'].length <= 0
  h
end

有没有更多的 ruby​​/rails 方式来完成这个?

【问题讨论】:

  • 除了未确定的JSON.parse(node.to_json),没关系
  • 也许可以试试node.as_json ?
  • 实际上不好的是它会导致许多数据库查询,这就是像祖先这样的宝石在一个查询中获取所有树成员的地方
  • @apneadiving 同意我问的问题;也就是说,我前段时间检查过那个宝石,因为它听起来像是首选;但如果我没记错的话,你不会得到多对多的处理,对吧?从 2012 年开始,但听起来像 github.com/stefankroes/ancestry/issues/94#issuecomment-6755069 它永远不会被计划
  • 虽然很多人在树上感觉很奇怪,但我能理解你会需要它

标签: ruby-on-rails arrays ruby object activerecord


【解决方案1】:

这样的事情应该会给你一些启发:

class Item < ApplicationRecord
  has_many :joins, dependent: :destroy
  has_many :child_items, through: :joins

  def as_json_iterated
    options = {}
    chain_length.times { options[:include] = {child_items: options} }
    as_json(options)
  end

  def chain_length(counter = 0)
    return counter if child_items.empty?
    child_items.map { |item| item.chain_length(counter + 1) }.max
  end

end

这会导致:

Item.find(1).as_json_iterated
#=> {
#     "id"=>1, 
#     "child_items"=>[{
#       "id"=>2, 
#       "child_items"=>[{
#         "id"=>4, 
#         "child_items"=>[{
#           "id"=>7,  
#           "child_items"=>[]
#         }]
#       }, {
#         "id"=>5, 
#         "child_items"=>[]
#       }]
#     }, {
#       "id"=>3,  
#       "child_items"=>[{
#         "id"=>6,
#         "child_items"=>[]
#       }]
#     }]
#   }

请记住,此方法的 SQL 性能很差。

有关 #as_json 选项的更多信息,请参阅:ActiveModel::Serializers::JSON#as_json

【讨论】:

  • 任何人都会承认糟糕的 sql 性能,问题是在这里获得更好的选择。虽然我不认为用例是那么邪恶(假设你大部分时间会深入挖掘 2 个级别,这只是保持进一步嵌套的能力),但我有点自欺欺人地没有看到一个像样的替代方案。查看序列化程序,在链接时再次检查;它为每个包含运行一个 sql 查询——如果我没有错,你会得到同样糟糕的性能。我可能没有寻找正确的方向,但我想知道
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
相关资源
最近更新 更多