RoR, нужно создавать рекурсивные отношения в табличных ассоциациях

0

Я очень новичок в рельсах, и я немного зациклился на логике этой проблемы.

У меня есть одна таблица (с использованием mysql) сотрудников, каждая из которых manager_id ключ manager_id который относится к сотруднику, которому они сообщают. Так, например, сотрудник с названием "CEO" с идентификатором 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

но это кажется слишком сложным.

  • 0
    Вы пытались использовать closure_tree или родословную ? Вы можете выполнить работу с любым из этих драгоценных камней, используя древовидную структуру данных.
Теги:
activerecord

1 ответ

0
Лучший ответ

Некоторые проблемы в методе getBelow

  • Вы всегда используете @root вместо использования param (root). Поэтому вы всегда начинаете снова с "CEO".

  • Вы вызываете getBelow рекурсивно, но вы не используете результат.

  • Вы вызываете @reports = Employee.where("manager_id =?", @root[:id]) дважды.

  • Вы возвращаетесь @root.

Как сказал Хорхе Наджера, есть драгоценные камни, которые легко справляются с древовидной структурой. Если вы хотите построить его самостоятельно, это мое предложение:

#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

Это не было проверено, поэтому я думаю, что вы получите некоторые ошибки, но я считаю, что идея в порядке.

  • 0
    Я только что принял ваш ответ, можете ли вы объяснить, что делает ветвь << узел, и почему «ветвь» сама по себе сразу после конца? Я еще не проверял это, но он будет в GET-запросе, поэтому я предполагаю, что могу просто передать любой идентификатор менеджера, чтобы получить любую желаемую подструктуру.
  • 0
    branch << node добавляет элемент (узел) в массив (ветвь). ветвь начинается как пустой массив и добавляет элементы внутри каждого цикла. Поскольку цикл вызывает getBelow (рекурсивно), сам узел может иметь много уровней (подветвлений). После end ветвь имеет все узлы, добавленные в цикл (и каждый узел может иметь подузлы, добавленные в рекурсивных вызовах). Вы можете передать любой manager_id для запуска и заменить элемент @root.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню