Rails, создающий древовидную структуру. Вывод в формате JSON

#ruby-on-rails #ruby #json #ruby-on-rails-3

#ruby-on-rails #ruby #json #ruby-on-rails-3

Вопрос:

у меня есть таблица данных, которые могут иметь друг друга в качестве родителей или дочерних элементов, она обрабатывается с помощью поля parent_id (я использую драгоценный камень act_as_tree)

элементы первого уровня имеют 0 в качестве parent_id

дочерних элементов может быть бесконечное количество. Я хочу выводить в формате JSON. конечный результат должен быть примерно таким

 {
   "feild1": "dd",
   "filed2": "ee",
   "child" : {
       "feild1": "dd",
        "filed2": "ee",
        } 
   "child" : {
        "feild1": "dd",
        "filed2": "ee",
                 "child" : {
                      "feild1": "dd",
                      "filed2": "ee",
                  } 
        } 

}
  

пока у меня есть только это

 def coa_tree
   @roots = Coa.find(:all, :conditions => ['parent_id = ?', 0])
   @response = @roots

   @roots.each do |root|
     logger.debug "roots each"
      output = root
      root.children.each do |child|
           output = {:child => output, :child => child}

      end

   end
   respond_with(@response)
end
  

очевидно, что я даже близко не подошел к решению проблемы. Если бы кто-нибудь мог указать мне правильное направление, я был бы очень признателен. возможно, есть плагин, о котором я не знаю, который помог бы мне решить эту проблему.
Спасибо.

Ответ №1:

Ваш пример JSON недопустим, потому что в одном объекте есть несколько ключей с одинаковым именем, но вывод древовидной структуры в виде JSON из объекта ActiveRecord определенно возможен.

Попробуйте добавить подобный метод в свой класс модели:

 class Coa < ActiveRecord::Base
  def to_node
    { "attributes" => self.attributes,
      "children"   => self.children.map { |c| c.to_node }
    }
  end
end
  

Теперь вы можете получить все дерево в формате JSON, используя:

 root = Coa.find(:first, :conditions => ["parent_id = ?", 0])
root.to_node.to_json
  

Комментарии:

1. спасибо, это помогло. и я предполагаю, что более чистым является наличие рекурсивной функции в модели.

Ответ №2:

Единственное, что я хотел бы добавить к ответу Тодда Янделла, это то, что может быть полезно не иметь отдельных ключей для «атрибутов» и «дочерних элементов». Другими словами, в то время как метод Янделла возвращал бы данные, подобные этому:

 {
   "attributes" : {
        "field1": "dd",
        "field2": "ee",
   "children" : [{
        "field1": "dd",
        "field2": "ee",
    }, {
        "field1": "dd",
        "field2": "ee",
    }, {
        "field1": "dd",
        "field2": "ee",
    }]
}
  

Возможно, вы пожелаете, чтобы данные в приведенном выше вопросе были отформатированы следующим образом:

 {
   "field1": "dd",
   "field2": "ee",
   "children" : [{
        "field1": "dd",
        "field2": "ee",
    }, {
        "field1": "dd",
        "field2": "ee",
    }, {
        "field1": "dd",
        "field2": "ee",
    }]
}
  

Этот формат особенно полезен в ситуациях, когда клиентский код ожидает данные в формате JSON в формате дерева и не позволяет гибко определять разные ключи для родительских атрибутов и дочерних элементов (например, компонент NestedList в Sencha Touch и т.д.).

Для достижения этой цели, основываясь на концепции Янделла, я придумал следующее:

 def to_node
  self.attributes.merge({:children => self.children.map { |c| c.to_node }})
end