2008-09-03 8 views
1

Existe-t-il un moyen rapide et propre de renvoyer un hachage JSON à partir de n'importe quel noeud d'un jeu acts_as_nested de Ruby on Rails sans utiliser la récursivité?Est-ce que Ruby peut convertir un acts_as_nested_set en un hachage JSON sans récursion?

est ici la solution récursive pour référence:

class Node < ActiveRecord::Base 
    has_many :products 
    def json_hash 
    if children.size > 0 
     children.collect { |node| { node.name => node.json_hash }.to_json 
    else 
     { node.name => node.products.find(:all).collect(&:name) }.to_json 
    end 
    end 
end 

Répondre

2

Il y a un wikipedia article sur traversal arbre qui montre les différentes alternatives à la solution récursive que vous utilisez. Il peut être difficile de les utiliser dans votre cas particulier, mais cela devrait être possible. Cependant, ma question est la suivante: y a-t-il une raison particulière pour laquelle vous voulez utiliser l'itération plutôt que la récursivité? Je ne pense pas que l'une des solutions itératives sera presque aussi propre. Vos arbres sont-ils si gros que vous manquez d'espace de pile (ils devraient être assez gros)? Sinon, je ne suis pas sûr qu'une solution itérative soit vraiment plus rapide.

Je vois un potentiel d'amélioration cependant, si vous voyez des problèmes de performance ... mais je ne sais pas rails, donc je ne suis pas sûr si elle est exacte:

Est-ce que la méthode de recherche, renvoie un nouveau tableau? Si oui, vous voulez probablement invoquer .collect! au lieu de .collect, car si find crée un tableau, vous créez simplement un tableau, puis vous le lancez dans l'appel de collection (qui crée également un tableau), ce qui ne va certainement pas être très efficace et peut vous ralentir beaucoup si vous avez un grand arbre là-bas.

Alors

{ node.name => node.products.find(:all).collect(&:name) }.to_json 

pourrait devenir

{ node.name => node.products.find(:all).collect!(&:name) }.to_json 

EDIT: En outre, il peut être plus efficace pour créer votre hachage de hachages, puis convertir le tout en JSON en 1 coup, plutôt que de le convertir en morceaux comme vous le faites.

Alors

class Node < ActiveRecord::Base 
    has_many :products 
    def json_hash 
    if children.size > 0 
     children.collect { |node| { node.name => node.json_hash }.to_json 
    else 
     { node.name => node.products.find(:all).collect!(&:name) }.to_json 
    end 
    end 
end 

pourrait devenir

class Node < ActiveRecord::Base 
    has_many :products 
    def json_hash 
    to_hash.to_json 
    end 

    def to_hash 
    if children.size > 0 
     children.collect { |node| { node.name => node.to_hash } 
    else 
     { node.name => node.products.find(:all).collect!(&:name) } 
    end 
    end 
end 

Que cela fonctionne et est plus efficace que je laisse comme un exercice pour vous ;-)

+0

Bonne réponse, mais je cherchais plus d'un moyen de Ruby itératif ou fantaisie pour le faire. – hoyhoy

1

JSONifier!

node.to_json(:include=>{:products=>{:include=>:product_parts}}) 
Questions connexes