【问题标题】:RoR, need to create recursive relationships in table associationsRoR,需要在表关联中创建递归关系
【发布时间】:2018-03-21 19:29:01
【问题描述】:

我对 Rails 很陌生,对这个问题的逻辑有点卡住了。

我有一张员工表(使用 mysql),每个员工都有一个 manager_id 键,表示他们向其报告的员工。例如,头衔为“CEO”的员工 id 为 1,manager_id 为 nil,头衔为“CTO”的员工 manager_id 为 1。所以我的记录如下所示

id: 1, first_name: "Bob", last_name: "Boss", title: "CEO", manager_id: null
id: 2, first_name: "Pat", last_name: "Guy", title: "CTO", manager_id: 1
id: 3, first_name: "John", last_name: "Dude", title: "VP of engineering", manager_id: 2

我的 JSON 结构应该是这样的

    [
    {id: 1, first_name: "Bob", last_name: "Boss", title: "CEO", manager_id: null, descendents: [
      {id: 2, first_name: "Pat", last_name: "Guy", title: "CTO", manager_id: 1, descendents: [
        {id: 3, first_name: "John", last_name: "Dude", title: "VP of engineering", manager_id: 2, descendents: [....]}
        ]},
      {..more CEO descendents...}
    ]

我正在尝试创建一个嵌套的 JSON 结构,该结构从 CEO 开始,列出向他们报告的所有员工,以及每个员工的后代。我试图编写一个创建它的脚本,但我不断收到无限的递归调用。这就是我所拥有的

        #start at some root
        @root = Employee.find_by title: 'CEO'
        #convert to hash table
        @results[0] = @root.attributes
        #add direct_reports key
        @results[0]["direct_reports"] = []

        def getBelow(root=@root)

            @reports = Employee.where("manager_id = ?", @root[:id])

            if @reports.blank?
                return []
            else
                @reports = @reports.map(&:attributes)
                @reports.each do |person|
                    person["direct_reports"] = []
                    getBelow(person)
                end
                @reports = Employee.where("manager_id = ?", @root[:id])
                root["direct_reports"] = @reports
            end

            return @root
        end

        @list = getBelow(@results[0])

如果我传入每个新的人对象,当@reports.blank? 变为真时,它们不应该全部结束吗?

我想到的另一种方法是使用受这篇博文启发的表关联

https://hashrocket.com/blog/posts/recursive-sql-in-activerecord

但这似乎有点太复杂了。

【问题讨论】:

  • 您是否尝试过使用closure_treeancestry?您可以使用树数据结构使用这些 gem 中的任何一个来完成工作。

标签: mysql ruby-on-rails activerecord


【解决方案1】:

getBelow 方法中的一些问题

  • 您总是使用@root,而不是使用参数(root)。所以你总是从“CEO”重新开始。

  • 您正在递归调用 getBelow,但您没有使用结果。

  • 您拨打@reports = Employee.where("manager_id = ?", @root[:id]) 两次。

  • 你返回@root。

正如 Jorge Najera 所说,有些宝石可以轻松处理树形结构。如果您想自己构建它,这是我的建议:

#start at some root
@root = Employee.find_by manager_id: nil

#convert to hash table
@tree = @root.attributes

#add direct_reports key
@tree["direct_reports"] = getBelow(@root)

def getBelow(manager)

  branch = []

  Employee.where("manager_id = ?", manager.id).each do |employee|
    node = employee.attributes
    node["direct_reports"] = getBelow(employee)
    branch << node
  end
  branch

end

这没有经过测试,所以我认为你会得到一些错误,但我相信这个想法是好的。

【讨论】:

  • 我刚刚接受了你的回答,你能解释一下分支
  • branch &lt;&lt; node 将一个元素(节点)添加到数组(分支)中。分支从一个空数组开始,并在每个循环内添加元素。当循环调用 getBelow(递归)时,节点本身可以​​有许多级别(子分支)。在end 之后,分支将所有节点都添加到循环中(并且每个节点都可以在递归调用中添加子节点)。您可以传递任何 manager_id 来启动,并替换 @root 元素。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多