There is a wikipedia article on tree traversal which shows different alternatives to the recursive solution you are using. It may be tricky to use them in your specific case, but it should be possible.
However, my question to you is, is there a specific reason you want to use iteration instead of recursion? I don't think any of the iterative solutions will be nearly as clean. Are your trees so big that you are running out of stack space (they would have to be pretty big)? Otherwise, I'm not so sure an iterative solution will really be faster.
I see one potential for improvement though, if you are seeing performance issues... but I don't know rails, so I'm not sure if it is accurate:
Does the find method return a new array? If so, you probably want to invoke .collect! instead of .collect, because if find creates an array, you are just creating an array and then throwing it away to the call to collect (which also creates an array), which surely is not going to be very efficient and may slow you down a lot if you have a big tree there.
So
{ node.name => node.products.find(:all).collect(&:name) }.to_json
might become
{ node.name => node.products.find(:all).collect!(&:name) }.to_json
EDIT: Also, it may be more efficient to create your hash of hashes, and then convert the whole thing to json in 1 fell swoop, rather than converting it piecemail like you are doing.
So
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
might become
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
Whether this works and is more efficient I leave as an exercise for you ;-)