Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How would you render a tree ? #70

Closed
simonc opened this issue Jul 19, 2011 · 13 comments
Closed

How would you render a tree ? #70

simonc opened this issue Jul 19, 2011 · 13 comments

Comments

@simonc
Copy link

simonc commented Jul 19, 2011

Hi,

I have a folders tree in my application and I would like to know how I could render it in json with rabl.
I guess I'll have to use a partial but I'm not sure how.

Any idea ?

Thanks !

@nesquena
Copy link
Owner

First decide how you'd like the final JSON to look in the API. Perhaps something like:

{ 'folder' => { 'subfolder' =>  { ... } }

Once you decide the JSON response you want, how you craft it in RABL will be im sorry to say probably very custom (and could use partials or not). It could be something like:

object false

node :tree do |m|
   @tree.folders.map { |folder| # ... build a hash here ... }
   # Really this can be anything, array, hash, etc 
end

Presumably that method might be elaborate but essentially my guess is a tree is going to be pretty custom so it amounts to just constructing the hash yourself either in the model or in the rabl output. I am not sure of a better way to do it unless you describe the breakdown of your models and/or the expected json output.

@simonc
Copy link
Author

simonc commented Jul 20, 2011

Ok, some more infos:

I use Mongoid::Tree to get the tree structure on the model side.
The simple JSON output I want for now should look like this:

[{ folder:
   {
     name: "some-name",
     children: [{ folder:
       {
          name: "some-sub-folder",
          children: []
       }
    }]
  }
},
{
  folder:
  {
    ...
  }
}]

For HTML it's just a simple partial calling itself. I was thinking about the same thing with rabl but it's maybe not the right way to do it with rabl.

What do you think ?

@jasonvasquez
Copy link

I have a similar situation, with arbitrarily deep nesting. The model is like:

class Node < ActiveRecord::Base
  has_many :children, :class_name => "Node", :foreign_key => "parent_id"
end

I'd like to render something like:

{"node":{
  "id":1,
  "name":"RootNode",
  "children":[
    {
      "id":2,
      "name":"Child 1 Level 1",
      "children":[
        {
          "id":3
          "name":"Child 1 Level 2",
          "children":[
            {
              "id":6
              "name":"Child 1 Level 3"
             }
          ]
         }
      ]
    },
    {
      "id":4,
      "name":"Child 2 Level 1",
      "children":[
        {
          "id":5
          "name":"Child 2 Level 2"
         }
      ]
    }
  ]
}

Is something like that possible? The solution doesn't seem immediately obvious to me.

@nesquena
Copy link
Owner

Couldn't this work with a recursive extends?

# node/show.json.rabl
attributes :id, :name
child :children => :children do
  extends "nodes/show"
end

Just an experiment to try, let me know if this works at all

@jasonvasquez
Copy link

This is very close! The only issue is that the nested children are all named "child", e.g. (pseudo):

node: {
    children: [
        child: {
            children: [ ]
        }
    ]
}

The desired output would be:

node: {
    children: [
        node: {
            children: [ ]
        }
    ]
}

The template looks like:

object @root_node => :node
attributes :id, :name, :parent_id
child :children => :children do
  extends "molecule/index"
end

Thoughts? (Thanks for the quick follow-up!)

@nesquena
Copy link
Owner

Alright how about:

object @root_node => :node
attributes :id, :name, :parent_id
child :children => :nodes do
  extends "molecule/index"
end

I think we are getting close :)

If not maybe a bit more manual with "node":

object @root_node => :node
attributes :id, :name, :parent_id
node :children do |n|
   n.children.map { |c| { :node => partial("molecule/index", :object => c) }  }
end

@jasonvasquez
Copy link

Ah hah! The 2nd form is perfect. I had tried several permutations of something similar, but had not hit upon the correct thing. :)

(The 1st form results in what was desired to be 'children' being named 'nodes')

Thanks again!

@robmathews
Copy link

Maybe update the docs? It's completely non-obvious how to do this, and I spent more than 2 hrs hacking around before I read this, and even this explanation is less than complete (ie, where did the template "molecule/index" come from? Is it the same as this template, or is it a different template only used for rendering the child and lower levels)

@nesquena
Copy link
Owner

Added the docs to link to this ticket in case others need to render a tree. If anyone can help with a wiki page for rendering a tree, I will link there instead.

@mockdeep
Copy link

Alright, so I'm trying to do something similar, but I don't have a root node, just a group of nodes, each of which is the root of a tree. Here's what I have so far:

# the root page, index.rabl
object false    

@elements.map do |element|    
  { :element => partial("elements/tree", :object => element) }    
end
# the partial, _tree.rabl
attributes :id, :title

node :children do |element|
  element.children.map do |child_element|
    { :element => partial("elements/tree", :object => child_element) }
  end 
end

The interesting thing is, if I print out the result in the log, it looks exactly like what I want, but then by the time it gets rendered to the client, I get an empty json object, {}. Any ideas what's going wrong?

@nesquena
Copy link
Owner

Can you try:

# index.rabl
collection @elements, :root => false, :object_root => "element"
extends "elements/tree"

and see how close that gets you?

@mockdeep
Copy link

That's perfect, thanks!

@vibgy
Copy link

vibgy commented Jun 30, 2013

Can someone please suggest changes in my code so that I can get the desired layout:

#desired output:
{"length":2,
 "agents":[
            {"object":"agent","firstName":"Sallie","lastName":"Bla","email":"agent@dantler.us","agentId":1},
            {"object":"agent","firstName":null,"lastName":null,"email":"new@dantler.xa","agentId":2}
             ]}

#what I'm getting is this:
{"length":2,
 "agents":[
            {"agent":{"object":"agent","firstName":"Sallie","lastName":"Bla","email":"agent@dantler.us","agentId":1}},
            {"agent":{"object":"agent","firstName":null,"lastName":null,"email":"new@dantler.xa","agentId":2}}
             ]}

# agents.rabl
object false
node (:length) {|m| @agents.length}

child @agents => "agents" do |x|
    extends 'agent'
end

# agent.rabl
object @agent => ""
node do |x|
{
    :object => "agent",
    :firstName => x.first_name,
    :lastName => x.last_name,
    :email => x.email,
    :agentId => x.id
}
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants