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

Comments

Projects
None yet
6 participants
@simonc

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

This comment has been minimized.

Show comment
Hide comment
@nesquena

nesquena Jul 19, 2011

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.

Owner

nesquena commented Jul 19, 2011

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

This comment has been minimized.

Show comment
Hide comment
@simonc

simonc 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 ?

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

This comment has been minimized.

Show comment
Hide comment
@jasonvasquez

jasonvasquez Sep 18, 2011

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.

jasonvasquez commented Sep 18, 2011

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

This comment has been minimized.

Show comment
Hide comment
@nesquena

nesquena Sep 18, 2011

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

Owner

nesquena commented Sep 18, 2011

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

This comment has been minimized.

Show comment
Hide comment
@jasonvasquez

jasonvasquez Sep 18, 2011

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!)

jasonvasquez commented Sep 18, 2011

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

This comment has been minimized.

Show comment
Hide comment
@nesquena

nesquena Sep 19, 2011

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
Owner

nesquena commented Sep 19, 2011

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

This comment has been minimized.

Show comment
Hide comment
@jasonvasquez

jasonvasquez Sep 19, 2011

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!

jasonvasquez commented Sep 19, 2011

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

This comment has been minimized.

Show comment
Hide comment
@robmathews

robmathews Nov 21, 2011

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)

robmathews commented Nov 21, 2011

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

This comment has been minimized.

Show comment
Hide comment
@nesquena

nesquena Nov 22, 2011

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.

Owner

nesquena commented Nov 22, 2011

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.

@nesquena nesquena closed this Mar 28, 2012

@mockdeep

This comment has been minimized.

Show comment
Hide comment
@mockdeep

mockdeep Sep 20, 2012

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?

mockdeep commented Sep 20, 2012

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

This comment has been minimized.

Show comment
Hide comment
@nesquena

nesquena Sep 20, 2012

Owner

Can you try:

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

and see how close that gets you?

Owner

nesquena commented Sep 20, 2012

Can you try:

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

and see how close that gets you?

@mockdeep

This comment has been minimized.

Show comment
Hide comment
@mockdeep

mockdeep Sep 20, 2012

That's perfect, thanks!

mockdeep commented Sep 20, 2012

That's perfect, thanks!

@vibgy

This comment has been minimized.

Show comment
Hide comment
@vibgy

vibgy 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

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