Reputation: 3659
I have Board model. Board can be subscribed to other boards (as a feed). Lets say I have board tree like this:
http://upload.wikimedia.org/wikipedia/commons/thumb/f/f7/Binary_tree.svg/200px-Binary_tree.svg.png
So:
Board.find(2).feeds
are boards 5 and 7
Board.find(7).feeds
are boards 2 and 6 etc.
I want to write method all_feeds
which returns all feeds from all levels for certain board. For example:
Board.find(7).all_feeds
would output array of boards with ids: 2,6,5,11
I started with something like:
def all_feeds
if feeds.empty?
return
else
feeds.each {|feed| feed.all_feeds}
return feeds
end
end
Probably have to add this return feeds to some global array, but not sure how should I do this.
Thanks for help.
ps. this is not always a binary tree, you can have more than 2 feeds.
Upvotes: 2
Views: 143
Reputation: 3999
I guess that what you want could be achieved with:
def all_feeds
unless feeds.empty?
feeds + feeds.map(&:all_feeds).flatten.compact
end
end
Array#flatten makes the result one-dimensional, while Array#compact removes the nil components.
For an explanation of the map(&:all_feeds)
part, you can refer to this SO answer :)
Upvotes: 1
Reputation: 3959
if it is allowed to use gems ancestry gem will help do the trick
Board.find(7).descendants
in this case it will be definitely one request to db without any recursion which is better for performance
you can implement ancestry idea without gem (or in top of it):
add ancestry
field to your model
fill it correctly when you build your tree (for nested nodes with ids 2 and 6 it will be 2/7
, with ids 5 and 11 - 2/7/6
)
and then just take it from db with like 2/%
query
Upvotes: 0
Reputation: 3659
Looks like it's working for below code:
def all_feeds
if feeds.empty?
self
else
[self]+feeds.map(&:all_feeds)
end
end
Upvotes: 1