Skip to content
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

has_closure_tree_root - Better tree eager loading #232

Merged
merged 4 commits into from
Oct 3, 2016

Conversation

smoyte
Copy link
Contributor

@smoyte smoyte commented Oct 2, 2016

So many times in working with trees I have a model, say Group, that has an associated tree, say of Users (say, with parent/child relationship defined by referral, as in the closure_tree specs). I keep a reference to the root of the tree, and would like to be able to load the root and all its descendants. I know that self_and_descendants can do this, but I want two things in addition:

  1. I don't want an array of nodes--I still want to be able to traverse the eager-loaded nodes using the familar .parent and .children methods. This is the way you're supposed to traverse a tree and this is how tree recursion typically and elegantly works.
  2. I still want to be able to eager load associations of the User class.

Unless I'm missing something, there is no way to do this currently. self_and_descendants gives you #2 but not #1.

This PR allows both. The basic idea is you declare:

has_closure_tree_root :root_user

This defines a plain has_one association to the root node (no preloading here), but also lets you do:

some_group.root_user_including_tree(contracts: :contract_type)

which loads all Users, Contracts, and ContractTypes in 4 queries, no matter how many nodes are in the tree. .parent and .children work as expected. Once the root is loaded, something like root.children[0].children[0].contracts[0].user.parent.parent.children[1].children[1].contracts[0].contract_type.name triggers zero queries (not that you would ever write this line directly, but you get the idea).

It also preloads the inverse belongs_to :group association on User, if that association is defined. So root.children[0].group also triggers zero queries.

I'm curious for your thoughts on this. It's been very useful in my projects and curious if you think it would be a useful addition.

And thanks for the always awesome closure_tree!

@mceachen mceachen merged commit 8f7f46a into ClosureTree:master Oct 3, 2016
@mceachen
Copy link
Collaborator

mceachen commented Oct 3, 2016

lgtm, thanks for making it both self-contained and well-tested.

@smoyte
Copy link
Contributor Author

smoyte commented Oct 3, 2016

Wow I wasn't expecting that to go so quickly! Thanks! I'd also be happy to add this to the Readme if you like. Will try to get to it soon.

@mceachen
Copy link
Collaborator

mceachen commented Oct 3, 2016

That would be splendid, thanks.

On Oct 3, 2016 6:34 AM, "Tom Smyth" notifications@github.com wrote:

Wow I wasn't expecting that to go so quickly! Thanks! I'd also be happy to
add this to the Readme if you like. Will try to get to it soon.


You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub
#232 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AANNOQojzmJYeG4GpKtXpK3YG6je80H8ks5qwQRmgaJpZM4KMEYR
.

@Exelord
Copy link

Exelord commented Oct 11, 2016

I can't wait when I implement this in my gem https://github.com/Exelord/Monarchy.
Awesome!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants