It's not easy -- I've done it -- but it's more efficient, and probably
the right thing to do for most use cases. Basically, you determine
the level of each node, and go from there.
Could you share some of the code? It would really help.
Jaap, as you've described your use case elsewhere as being a
progressive drilldown, you may actually want to use the less efficient
structure here -- I'm not sure. However, using nested sets will mean
that you're not stuck with that through your whole application.
The thing is, elsewhere in my application I will have to go -a lot-
deeper than this. Certain attributes have other functionality than
others and I will need to be able to visualize some attributes as a
table component instead of a list item, for example.
> > What I can come up right now is a way to cut the calls down to the
> > number of nodes with children with something like:
> > """
> > def my_awesome_helper(root)
> > result = "<ul>" + "<li>" + root.someattribute
> > if root.children {
> > root.children.each do |child|
> > result += my_awesome_helper(child)
> > end
> > end
> > result += "</li>" + "</ul>"
> > end
> > """
> > (yeah, ugly, and I'm not even sure the syntax is right, but you get
> > the idea)
> > You'd then just have to call the helper on the root node in your view.
> > Mit freundlichen Grüßen,
> > Felix Schäfer
> Danke Felix!
> I'm quite unsure whether this would limit the number of queries.
Instead of posting that you're "quite unsure" whether this would work,
try it and find out.
I did, of course, but it makes just as many queries as far as I can
see. It will make one query for all children, that's true, but my
first implementation did that too. If you call children.each it will
generate one query for all those children. However, any grandchildren
(lol) will need a seperate query.
However, this brought me an idea: I hope I got this right of course,
but based on my perception of a nested set, I could get all
descendants, order them by "lft" and do something like
descendants.each do |attribute| and send along the attribute's id. If
the parent_id of the next attribute matches this id, it's a child,
otherwise it's a sibling. However, this makes awesome nested set a
very limited plugin and if this is the only way this could be done, it
could really do with some improvements.
I will first try this in my views, so I'll get back to you on this,
but it's not pretty and I do not prefer to do it this way.
> I
> already call children.each in my views, so this would probably, in
> terms of performance, won't really help me.
I think it will help, if you've already fetched the whole set. I
believe (but am not absolutely certain) that the tree is cached, so
once you do @root.descendants, the whole thing is fetched, and
@root.children[0].children will not generate another query. Again,
try it and watch the SQL.
It does. It won't generate a query for @root.descendants, but for
@root.children and for @root.children[0].children. Only if you say
@attributes = @root.children and, for example, do something like:
<% @attributes.each do |attribute| %>
<%= attribute.name %>
<% end %>
.. it will not generate another query after defining @attributes. But
that still means I will have to work with alot of queries.
> I was told I could perform
> this using one single query, but that seems impossible.
What's impossible about it?
Well, there's no way I know of to be able to say @attributes =
@root.descendants and use the functionality of awesome nested set to
descend into my sets without generating alot of queries. In fact,
stating @attributes = @root.descendants doesn't do anything, according
to my logs. The only thing I could do with it is manually handling
every row and checking whether its parent_id is the same as the last
row's id. I don't need a a nested set plugin for that!
> And that
> brings me back to a point where I question the advantages of using
> awesome_nested_set over using acts_as_tree in combination with
> acts_as_list.
At this point, you're going around in circles. Stop theorizing and
actually write some code.
Why do you assume I didn't? I've tried it and compared logs. It
doesn't do anything different query-wise.
Thank you for your help, I really appreciate it.