RoR,需要在表关联中创建递归关系

时间:2018-03-21 19:29:02

标签: mysql ruby-on-rails activerecord

我对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...}
    ]

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

        #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

但这看起来有点太复杂了。

1 个答案:

答案 0 :(得分:0)

getBelow方法中的一些问题

  • 您总是使用@root,而不是使用param(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

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

相关问题