From philippe.lang at attiksystem.ch Mon Dec 11 10:53:04 2006 From: philippe.lang at attiksystem.ch (Philippe Lang) Date: Mon, 11 Dec 2006 16:53:04 +0100 Subject: [Betternestedset-talk] def parent=(new_parent) Message-ID: <6C0CF58A187DA5479245E0830AF84F421D15CB@poweredge.attiksystem.ch> Hi, Thanks for better_nested_set first. Is is REALLY better! I read about "add_child" that will be deprecated soon, replaced by "move_to_child_of". My english is not that fantastic, but I'm a little bit puzzled when I read: node.move_to_child_of(another_node) "Move the node to the child of a new node". It gives me the impression my node will have as a parent a child of the new node. Maybe en english speaker can help here. Maybe "move_as_child_of" instead? What do you think of the following: def parent=(new_parent) self.move_to_child_of(new_parent) end Since "def parent" already exists, API get symmetrical. And for me, it gets clear! ---------------------------------- Philippe Lang, Ing. Dipl. EPFL Attik System rte de la Fonderie 2 1700 Fribourg Switzerland http://www.attiksystem.ch Tel : +41 (26) 422 13 75 Fax : +41 (26) 422 13 76 Skype: philippe.lang -------------- next part -------------- A non-text attachment was scrubbed... Name: smime.p7s Type: application/x-pkcs7-signature Size: 3125 bytes Desc: not available Url : http://rubyforge.org/pipermail/betternestedset-talk/attachments/20061211/8020b602/attachment.bin From dontfall at gmail.com Tue Dec 12 19:23:30 2006 From: dontfall at gmail.com (Krishna Dole) Date: Tue, 12 Dec 2006 19:23:30 -0500 Subject: [Betternestedset-talk] def parent=(new_parent) In-Reply-To: <6C0CF58A187DA5479245E0830AF84F421D15CB@poweredge.attiksystem.ch> References: <6C0CF58A187DA5479245E0830AF84F421D15CB@poweredge.attiksystem.ch> Message-ID: <8d64b97d0612121623g539ef1d5p500b1d25b5d93aa6@mail.gmail.com> Hi Philippe, Thanks for the encouraging words! I'm a native english speaker, and I agree that move_to_child_of(node) isn't as clear as parent=(node). However, it is consistent with the other move_to methods. Also, in normal ActiveRecord associations, when you call parent=, the change doesn't take effect until the object is saved, but the move_to methods are immediate, and lose any unsaved changes in the object. I like the fact that the move_to methods remind the user that they cause an immediate change in tree structure. I've updated the documentation to make it clearer what the method does. It now reads: move_to_child_of(target) "Make this node a child of target (you can pass an object or just an id). Unsaved changes in either object will be lost. Raises ActiveRecord::ActiveRecordError if it encounters a problem." Hopefully that helps. Please feel free to keep bugging us with feedback. In fact, the current code (on rubyforge) needs beta-testers-- if you feel like trying to break it, just: script/plugin install svn://rubyforge.org/var/svn/betternestedset/trunk Cheers, Krishna On 12/11/06, Philippe Lang wrote: > Hi, > > Thanks for better_nested_set first. Is is REALLY better! > > I read about "add_child" that will be deprecated soon, replaced by "move_to_child_of". My english is not that fantastic, but I'm a little bit puzzled when I read: > > node.move_to_child_of(another_node) > > "Move the node to the child of a new node". It gives me the impression my node will have as a parent a child of the new node. Maybe en english speaker can help here. Maybe "move_as_child_of" instead? > > What do you think of the following: > > def parent=(new_parent) > self.move_to_child_of(new_parent) > end > > Since "def parent" already exists, API get symmetrical. And for me, it gets clear! > > ---------------------------------- > Philippe Lang, Ing. Dipl. EPFL > Attik System > rte de la Fonderie 2 > 1700 Fribourg > Switzerland > http://www.attiksystem.ch > > Tel : +41 (26) 422 13 75 > Fax : +41 (26) 422 13 76 > Skype: philippe.lang > > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/betternestedset-talk/attachments/20061212/2b9066d7/attachment.html From dontfall at gmail.com Tue Dec 12 20:03:51 2006 From: dontfall at gmail.com (Krishna Dole) Date: Tue, 12 Dec 2006 20:03:51 -0500 Subject: [Betternestedset-talk] Questions, RC for 0.1? Message-ID: <8d64b97d0612121703t77d2de10wb3e44db6b2004d7a@mail.gmail.com> Hi JCM et al., I've been committing a bunch of changes over the last few days, and we're down to one ticket on trac now, so I think we should start considering the current code as a release candidate for 0.1. I've come across some things I wanted to ask about, though. First of all, I think that #move_to_child_of should insert the new child to the right of existing children. Here's why: - consistent with the creation of new records (to the right of existing ones) - consistent with #add_child - consistent with default ordering for things like threaded posts, where new items are added after existing ones - if the parent has a large number of children relative to the size of the tree, performance will be better, because fewer rows need to be updated What do you think? I know this will be a compatibility issue, so if we are going to do it perhaps we should wait until after 0.1. The second thing I want to talk about would also cause compatibility problems. ;) It concerns #children_count. The present name of the method is highly misleading, because it actually counts _all_ children of the node, so presently node.children.size != node.children_count. If we are going to change it to #all_children_count, I would favor changing it to the much more natural #count_all_children instead. (I would also change #leaves_count to #count_leaves). Thoughts? The third issue concerns concurrency problems. Prior to revision 25, the following code would corrupt the left/right indexes: c1, c2, c3 = Category.create, Category.create, Category.create c1.move_to_right_of(c3) c2.save # c2 is stale, and overwrites the correct lft/rgt values My solution was to override the #update method in ActiveRecord to ignore the lft/rgt columns (the code is at the bottom of better_nested_set.rb). I don't know if this is a good way to do things, so I'm hoping that someone else can take a look at the code and see if it is sane. Cheers, Krishna From jc.michel at symetrie.com Tue Dec 12 22:04:20 2006 From: jc.michel at symetrie.com (Jean-Christophe Michel) Date: Wed, 13 Dec 2006 04:04:20 +0100 Subject: [Betternestedset-talk] Questions, RC for 0.1? In-Reply-To: <8d64b97d0612121703t77d2de10wb3e44db6b2004d7a@mail.gmail.com> References: <8d64b97d0612121703t77d2de10wb3e44db6b2004d7a@mail.gmail.com> Message-ID: <107cff9da4313f2779f840d4f89c79c6@symetrie.com> Hi Krishna, Le 13 d?c. 06, ? 02:03, Krishna Dole a ?crit : > I've been committing a bunch of changes over the last few days, and > we're down to one ticket on trac now, so I think we should start > considering the current code as a release candidate for 0.1. Sure, you've done a considerable amount of work. Many thanks ! > First of all, I think that #move_to_child_of should insert the new > child to the right of existing children. Here's why: > - consistent with the creation of new records (to the right of > existing ones) > - consistent with #add_child > - consistent with default ordering for things like threaded posts, > where new items are added after existing ones > - if the parent has a large number of children relative to the size of > the tree, performance will be better, because fewer rows need to be > updated > > What do you think? I know this will be a compatibility issue, so if we > are going to do it perhaps we should wait until after 0.1. why not. Let's change this before 0.1. > The second thing I want to talk about would also cause compatibility > problems. ;) It concerns #children_count. The present name of the > method is highly misleading, because it actually counts _all_ children > of the node, so presently node.children.size != node.children_count. > If we are going to change it to #all_children_count, I would favor > changing it to the much more natural #count_all_children instead. (I > would also change #leaves_count to #count_leaves). Thoughts? I copied behaviour as much as possible from acts_as_tree. I agree the meaning is not clear. If we choose to break acts_as_tree similarity, we can rename it. Or do we need to open a better_acts_as_tree project ? ;-) > The third issue concerns concurrency problems. Prior to revision 25, > the following code would corrupt the left/right indexes: > > c1, c2, c3 = Category.create, Category.create, Category.create > c1.move_to_right_of(c3) > c2.save # c2 is stale, and overwrites the correct lft/rgt values > > My solution was to override the #update method in ActiveRecord to > ignore the lft/rgt columns (the code is at the bottom of > better_nested_set.rb). I don't know if this is a good way to do > things, so I'm hoping that someone else can take a look at the code > and see if it is sane. Don't you think we'll solve the problem by defining attr_reader left_column_name or maybe, define #{left_column}=() {} method so none of left, right and parent could be set from code (only changed from sql) DId you try this already ? Jean-Christophe Michel -- symetrie.com Better Nested Set for rails: http://opensource.symetrie.com/trac/better_nested_set From dontfall at gmail.com Fri Dec 15 13:32:52 2006 From: dontfall at gmail.com (Krishna Dole) Date: Fri, 15 Dec 2006 13:32:52 -0500 Subject: [Betternestedset-talk] Questions, RC for 0.1? In-Reply-To: <107cff9da4313f2779f840d4f89c79c6@symetrie.com> References: <8d64b97d0612121703t77d2de10wb3e44db6b2004d7a@mail.gmail.com> <107cff9da4313f2779f840d4f89c79c6@symetrie.com> Message-ID: <8d64b97d0612151032m1c630872p9ef1ea825e674e8d@mail.gmail.com> Hi Jean-Christophe, Sorry to be so slow in responding. > why not. Let's change this before 0.1. OK, I'll make move_to_child_of insert on the right. > I copied behaviour as much as possible from acts_as_tree. Ah, I see that now. I suppose remaining consistent with the other counter cache methods in rails is good. You are OK with changing it to all_children_count, correct? (since the current name is inconsistent with both acts_as_tree and our other methods) > Don't you think we'll solve the problem by defining > attr_reader left_column_name You mean so that when ActiveRecord goes to update, it gets nil for the column values? That would still be a problem, because it would then set the values to NULL. > or maybe, define #{left_column}=() {} method > so none of left, right and parent could be set from code (only changed > from sql) We already prevent external assignment of lft/rgt, and ActiveRecord needs to set those attributes when a record if fetched. The problem is not that the values are being changed in the object, but that they are being changed in the database when a separate object is moved/deleted, and then if the record is saved, the (now incorrect) values get written back to the database. ActiveRecord does not appear to have any predefined way to exclude particular columns from the update statement, hence my hack. Please let me know if I've failed to see how the above might work. I'm excited about how things are shaping up. Cheers, Krishna > > Jean-Christophe Michel > -- > symetrie.com > > Better Nested Set for rails: > http://opensource.symetrie.com/trac/better_nested_set > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > From philippe.lang at attiksystem.ch Thu Dec 21 04:30:19 2006 From: philippe.lang at attiksystem.ch (Philippe Lang) Date: Thu, 21 Dec 2006 10:30:19 +0100 Subject: [Betternestedset-talk] move_to_child_of(nil) Message-ID: <6C0CF58A187DA5479245E0830AF84F421D1629@poweredge.attiksystem.ch> Hi, I'm trying to change a child node into a root node, by doing a "move_to_child_of(nil)". Apparently, it does not work. Is there another of doing that maybe? Thanks, --------------- Philippe Lang Attik System -------------- next part -------------- A non-text attachment was scrubbed... Name: smime.p7s Type: application/x-pkcs7-signature Size: 3125 bytes Desc: not available Url : http://rubyforge.org/pipermail/betternestedset-talk/attachments/20061221/0b03ca49/attachment.bin From dontfall at gmail.com Thu Dec 21 09:20:56 2006 From: dontfall at gmail.com (Krishna Dole) Date: Thu, 21 Dec 2006 09:20:56 -0500 Subject: [Betternestedset-talk] move_to_child_of(nil) In-Reply-To: <6C0CF58A187DA5479245E0830AF84F421D1629@poweredge.attiksystem.ch> References: <6C0CF58A187DA5479245E0830AF84F421D1629@poweredge.attiksystem.ch> Message-ID: <8d64b97d0612210620ne1945fco1de8ede5af227a7b@mail.gmail.com> Hi Philippe, Using "move_to_right_of(root)" or "move_to_left_of(root)" should work. Do you think that we should add the ability to use "move_to_child_of(nil)"? How does everyone else on the list feel about this? Krishna On 12/21/06, Philippe Lang wrote: > Hi, > > I'm trying to change a child node into a root node, by doing a "move_to_child_of(nil)". Apparently, it does not work. Is there another of doing that maybe? > > Thanks, > > --------------- > Philippe Lang > Attik System > > > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > > From philippe.lang at attiksystem.ch Thu Dec 21 10:05:22 2006 From: philippe.lang at attiksystem.ch (Philippe Lang) Date: Thu, 21 Dec 2006 16:05:22 +0100 Subject: [Betternestedset-talk] move_to_child_of(nil) Message-ID: <6C0CF58A187DA5479245E0830AF84F421D162D@poweredge.attiksystem.ch> betternestedset-talk-bounces at rubyforge.org wrote: > Hi Philippe, > > Using "move_to_right_of(root)" or "move_to_left_of(root)" should work. > > Do you think that we should add the ability to use > "move_to_child_of(nil)"? How does everyone else on the list > feel about this? Hi, I have the feeling it wouldn't be too bad, but maybe another function called move_to_root() would be better? --------------- Philippe Lang Attik System -------------- next part -------------- A non-text attachment was scrubbed... Name: smime.p7s Type: application/x-pkcs7-signature Size: 3125 bytes Desc: not available Url : http://rubyforge.org/pipermail/betternestedset-talk/attachments/20061221/198a5e3e/attachment.bin From jc.michel at symetrie.com Thu Dec 21 11:41:07 2006 From: jc.michel at symetrie.com (Jean-Christophe Michel) Date: Thu, 21 Dec 2006 17:41:07 +0100 Subject: [Betternestedset-talk] move_to_child_of(nil) In-Reply-To: <6C0CF58A187DA5479245E0830AF84F421D162D@poweredge.attiksystem.ch> References: <6C0CF58A187DA5479245E0830AF84F421D162D@poweredge.attiksystem.ch> Message-ID: Hi all, Le 21 d?c. 06, ? 16:05, Philippe Lang a ?crit : > betternestedset-talk-bounces at rubyforge.org wrote: >> Hi Philippe, >> >> Using "move_to_right_of(root)" or "move_to_left_of(root)" should work. >> >> Do you think that we should add the ability to use >> "move_to_child_of(nil)"? How does everyone else on the list >> feel about this? > > Hi, > > I have the feeling it wouldn't be too bad, but maybe another function > called move_to_root() would be better? I agree on the move_to_root() name,should it be only an alias for move_to_right_of(root). Jean-Christophe Michel -- symetrie.com Better Nested Set for rails: http://opensource.symetrie.com/trac/better_nested_set From dontfall at gmail.com Thu Dec 21 13:42:31 2006 From: dontfall at gmail.com (Krishna Dole) Date: Thu, 21 Dec 2006 13:42:31 -0500 Subject: [Betternestedset-talk] move_to_child_of(nil) In-Reply-To: References: <6C0CF58A187DA5479245E0830AF84F421D162D@poweredge.attiksystem.ch> Message-ID: <8d64b97d0612211042w1fbc273eqfcd1f9dad1981a4f@mail.gmail.com> Sounds good. On 12/21/06, Jean-Christophe Michel wrote: > Hi all, > > Le 21 d?c. 06, ? 16:05, Philippe Lang a ?crit : > > betternestedset-talk-bounces at rubyforge.org wrote: > >> Hi Philippe, > >> > >> Using "move_to_right_of(root)" or "move_to_left_of(root)" should work. > >> > >> Do you think that we should add the ability to use > >> "move_to_child_of(nil)"? How does everyone else on the list > >> feel about this? > > > > Hi, > > > > I have the feeling it wouldn't be too bad, but maybe another function > > called move_to_root() would be better? > > I agree on the move_to_root() name,should it be only an alias for > move_to_right_of(root). > > Jean-Christophe Michel > -- > symetrie.com > > Better Nested Set for rails: > http://opensource.symetrie.com/trac/better_nested_set > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > From linicks at gmail.com Thu Dec 21 17:39:46 2006 From: linicks at gmail.com (Nick Pavlica) Date: Thu, 21 Dec 2006 15:39:46 -0700 Subject: [Betternestedset-talk] Application suggestions Message-ID: All, I'm currently developing an application that is very dependent on hierarchical data. In this application I will have 500,000+ trees(roots), with an average range of 1-20+ data members (children + leaf nodes) for each tree. In this application, there will be more reads than writes, but will still have a fair number of writes, mostly just adding additional objects to the end of the hierarchy. Essentially, it would be like a forum where you have a very large number of root threads, and a fairly small number of threads underneath it (1-100 replies). Currently, in my beta I'm using act_as_tree (adjacent list) with out any problems, but it's just me and some test data. Eventually, there will around 1,000 concurrent users reading, traversing, and changing the hierarchies/trees. After doing some research on the topic I discovered this plug-in, and started to learn about nested sets. During my research I noticed that many authors highlight that read performance in greatly enhanced with nested sets, while write performance was greatly reduced especially as the tree grows. They also point out that a write requires a table lock (http://dev.mysql.com/tech-resources/articles/hierarchical-data.html) which seems like a pretty high cost when used in a situation where the hierarchy will change fairly regularly as opposed to something like a menu system. For my application, which of these methods is the best fit? Is there a better method out there for my application? I have been bouncing back and forth on the strengths of each method for my application. I appreciate any advice you have to offer! A couple of notes: - Currently using Postgresql 8.1 and plan to move to 8.2 - Currently developing with Rails 1.2RC Thanks! --Nick From dontfall at gmail.com Fri Dec 22 00:17:33 2006 From: dontfall at gmail.com (Krishna Dole) Date: Fri, 22 Dec 2006 00:17:33 -0500 Subject: [Betternestedset-talk] Application suggestions In-Reply-To: References: Message-ID: <8d64b97d0612212117r510644d6jc08beeabc2ae233@mail.gmail.com> Hi Nick, I'm glad you're interested in Better Nested Set. I think a nested set would serve you well because 1) most of your writes will be to the far right of your trees 2) your trees will be small, and 3) reads will greatly outnumber writes (which is almost always the case in web apps). It sounds like you have a good grasp of this, but it's worth restating exactly what types of update operations nested sets can and can't do quickly. At one extreme, adding a child node at the far right of the tree is almost as fast as it would be in an adjacency list setup, because only one additional row in the table (the root) needs to be updated. Same goes for swapping two adjacent nodes. At the other extreme lie things like inserting a node on the far left of a large tree, moving a branch from one side of the tree to the other, etc. All of these require updating every record in the tree. The application where I use nested sets stores about 16,000 records in a single tree, and the 'worst case' operations take a few seconds to complete. I'm happy to put up with that, because the rapid query abilities allow me to do things that would otherwise be not just slow, but impossible. I think you should try better_nested_set, but I don't think you should take my word for it-- do some benchmarking with acts_as_tree, then try nested sets. Moving to Better Nested Set should be fairly easy, since the API is very similar. (Of course, you will only see performance improvements if you start using the new query methods that Better Nested Set provides, or writing your own that use the left/right values.) Regarding your concerns about high concurrency: I've taken pains to ensure that the code is concurrency-safe (all index-altering methods are wrapped in transactions), and I think performance should be fine. But again, I'd benchmark it. I should also mention that there has been talk on the rails list of writing a tree plugin that uses materialized paths for improved write performance, but that hasn't happened yet. The good news is that the materialized path API should be fully compatible with Better Nested Set, so you can swap one for the other to fit your needs. In any case let us know how it goes! Cheers, Krishna On 12/21/06, Nick Pavlica wrote: > All, > I'm currently developing an application that is very dependent on > hierarchical data. In this application I will have 500,000+ > trees(roots), with an average range of 1-20+ data members (children + > leaf nodes) for each tree. In this application, there will be more > reads than writes, but will still have a fair number of writes, mostly > just adding additional objects to the end of the hierarchy. > Essentially, it would be like a forum where you have a very large > number of root threads, and a fairly small number of threads > underneath it (1-100 replies). > > Currently, in my beta I'm using act_as_tree (adjacent list) with out > any problems, but it's just me and some test data. Eventually, there > will around 1,000 concurrent users reading, traversing, and changing > the hierarchies/trees. After doing some research on the topic I > discovered this plug-in, and started to learn about nested sets. > During my research I noticed that many authors highlight that read > performance in greatly enhanced with nested sets, while write > performance was greatly reduced especially as the tree grows. They > also point out that a write requires a table lock > (http://dev.mysql.com/tech-resources/articles/hierarchical-data.html) > which seems like a pretty high cost when used in a situation where the > hierarchy will change fairly regularly as opposed to something like a > menu system. > > For my application, which of these methods is the best fit? Is there > a better method out there for my application? I have been bouncing > back and forth on the strengths of each method for my application. I > appreciate any advice you have to offer! > > A couple of notes: > - Currently using Postgresql 8.1 and plan to move to 8.2 > - Currently developing with Rails 1.2RC > > Thanks! > --Nick > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > From linicks at gmail.com Fri Dec 22 16:50:47 2006 From: linicks at gmail.com (Nick Pavlica) Date: Fri, 22 Dec 2006 14:50:47 -0700 Subject: [Betternestedset-talk] Application suggestions In-Reply-To: <8d64b97d0612212117r510644d6jc08beeabc2ae233@mail.gmail.com> References: <8d64b97d0612212117r510644d6jc08beeabc2ae233@mail.gmail.com> Message-ID: Krishna, Thanks for this great reply! I have been trying to move from acts_as_tree to better_nested_sets, but haven't been able to work through the details. This is mostly due to the fact that I'm fairly new to Rails and Ruby. I was using the following code segments to create sub_projects with acts_as_tree: _____________Add sub project Link_____________ <%= link_to ' > Add A Sub-Project ', :controller => 'project', :action => "new_subproject", :project_id => @project %>
______________Model_________________ acts_as_tree :order => "name" ______________Form_______________ <%= hidden_field 'project', 'parent_id', :value => @parent.id %> ______________Controller____________________________ def new_subproject @project = Project.new @parent = Project.find(params[:project_id]) end def create_subproject @project = Project.new(params[:project]) if @project.save #@project.move_to_child_of flash[:notice] = 'Project was successfully created.' redirect_to :action => 'list' else render :action => 'new' end end ________________________Helper__________________________ <%= (find_all_subprojects at project) %> def find_all_subprojects(project) if project.children.size > 0 ret = '
    ' project.children.each { |subprj| if subprj.children.size > 0 ret += '
  • ' ret += link_to h(subprj.name), :action => 'manage', :id => subprj ret += find_all_subprojects(subprj) ret += '
  • ' else ret += '
  • ' ret += link_to h(subprj.name), :action => 'manage', :id => subprj ret += '
  • ' end } ret += '
' end end After installing the Better Nested Sets plug-in and adding (acts_as_nested_set :order => "name") to my Project model, the new records were being created with the root boundaries being populated in the lft and rgt columns. The parent_id field wasn't being populated any more, but that was to be expected. The main portion that I can't seem to get past is when I try to make the subproject a child of what should be it's parent (move_to_child_of) after the save. @project.move_to_child_of ???? Can you point me in the right direction, it would be much appreciated. Thanks! --Nick From jc.michel at symetrie.com Fri Dec 22 18:41:21 2006 From: jc.michel at symetrie.com (Jean-Christophe Michel) Date: Sat, 23 Dec 2006 00:41:21 +0100 Subject: [Betternestedset-talk] Application suggestions In-Reply-To: References: <8d64b97d0612212117r510644d6jc08beeabc2ae233@mail.gmail.com> Message-ID: Hi Nick, Le 22 d?c. 06, ? 22:50, Nick Pavlica a ?crit : > In this application I will have 500,000+ > trees(roots), with an average range of 1-20+ data members (children + > leaf nodes) for each tree. Are your root trees ordered or not ? If they aren't, use the :scope to store your 500,000 trees in the same table, without interaction between each of them. This should be very efficient. > The main portion that I can't > seem to get past is when I try to make the subproject a child of > what should be it's parent (move_to_child_of) after the save. > > @project.move_to_child_of ???? > > Can you point me in the right direction, it would be much appreciated. Pass an id or an object of the new parent. Jean-Christophe Michel -- symetrie.com Better Nested Set for rails: http://opensource.symetrie.com/trac/better_nested_set From linicks at gmail.com Fri Dec 22 20:09:39 2006 From: linicks at gmail.com (Nick Pavlica) Date: Fri, 22 Dec 2006 18:09:39 -0700 Subject: [Betternestedset-talk] Application suggestions In-Reply-To: References: <8d64b97d0612212117r510644d6jc08beeabc2ae233@mail.gmail.com> Message-ID: > Are your root trees ordered or not ? I don't think that they are ordered. Essentially, I have a chain of sub_projects where I can have one or more sub projects at the same level with an unlimited depth, but the aren't specifically ordered. If they aren't, use the :scope to > store your 500,000 trees in the same table, without interaction between > each of them. This should be very efficient. Not quite sure what you mean here? But are you saying something like :scope => parent_id ? > > The main portion that I can't > > seem to get past is when I try to make the subproject a child of > > what should be it's parent (move_to_child_of) after the save. > > > > @project.move_to_child_of ???? > > > > Can you point me in the right direction, it would be much appreciated. > > Pass an id or an object of the new parent. I'm able to assign a child when I'm at the console, as described on the Wiki. I can also do it manually in my create subproject_method: @project.move_to_child_of 1. But when I try to assign a variable in my create_subproject method from the request parameters, I get a variety of errors. I'm not sure where I'm dropping the ball yet :) Here is my current create method def create_subproject @project = Project.new(params[:project]) @parent = (params[:parent_id]) #@parent = @project.parent_id if @project.save @project.move_to_child_of @parent flash[:notice] = 'Project was successfully created.' redirect_to :action => 'list' else render :action => 'new' end end I get this error : Couldn't find Project without an ID of course "parent_id"=>"1" is in the request parameters list in the debug message. I tried passing the value with the submit button on the form: <%= submit_tag "Create", :project_id => @parent.id; %> Where parent.id is set with the new method. This was how I was inserting the parent ID when using acts_as_tree. Thanks ! --Nick From dontfall at gmail.com Fri Dec 22 21:25:05 2006 From: dontfall at gmail.com (Krishna Dole) Date: Fri, 22 Dec 2006 21:25:05 -0500 Subject: [Betternestedset-talk] Application suggestions In-Reply-To: References: <8d64b97d0612212117r510644d6jc08beeabc2ae233@mail.gmail.com> Message-ID: <8d64b97d0612221825v37cea31dy3cf60495a6e3c40c@mail.gmail.com> Hi Nick, On 12/22/06, Nick Pavlica wrote: > If they aren't, use the :scope to > > store your 500,000 trees in the same table, without interaction between > > each of them. This should be very efficient. > Not quite sure what you mean here? But are you saying something like > :scope => parent_id ? The issue is that you could store all your little trees as one giant tree (with multiple roots) but write performance would be _terrible_, 'cause you'd be updating hundreds of thousands of rows each time. You need to specify a scope if you have more than one tree, so that the code knows which nodes belong in which tree. All members of a tree must have the same scope value (in your case something like root_project_id, it sounds like). > > Here is my current create method > > def create_subproject > @project = Project.new(params[:project]) > @parent = (params[:parent_id]) > #@parent = @project.parent_id > > if @project.save > @project.move_to_child_of @parent > flash[:notice] = 'Project was successfully created.' > redirect_to :action => 'list' > else > render :action => 'new' > end > end > Your code looks good, but if you haven't changed the form the parent is probably coming in as params[:project[:parent_id]] instead of params[:parent_id] If that doesn't work, put a 'breakpoint' before the save and run script/breakpointer to check out your params and see what's happening. cheers, Krishna From jc.michel at symetrie.com Sat Dec 23 09:04:54 2006 From: jc.michel at symetrie.com (Jean-Christophe Michel) Date: Sat, 23 Dec 2006 15:04:54 +0100 Subject: [Betternestedset-talk] Application suggestions In-Reply-To: References: <8d64b97d0612212117r510644d6jc08beeabc2ae233@mail.gmail.com> Message-ID: <251163542b548a2a8960f2baa7df7838@symetrie.com> Hi Nick, Le 23 d?c. 06, ? 02:09, Nick Pavlica a ?crit : > I get this error : Couldn't find Project without an ID > > of course "parent_id"=>"1" is in the request parameters list in the > debug message. So here is the error: your param is a string and find wants a Fixnum. Change params[:parent_id] to params[parent_id].to_i Jean-Christophe Michel -- symetrie.com Better Nested Set for rails: http://opensource.symetrie.com/trac/better_nested_set From linicks at gmail.com Wed Dec 27 17:58:59 2006 From: linicks at gmail.com (Nick Pavlica) Date: Wed, 27 Dec 2006 15:58:59 -0700 Subject: [Betternestedset-talk] A couple of questions Message-ID: All, I'm trying to work out a couple of details regarding the use of the better_nested_sets plugin. I have made progress in converting my code from acts_as_tree, but need help solving a couple of problems. 1. When I try to get the children of the root object, I'm able to count them but don't get any return values for children, all_children, etc. >> prj = Project.find_by_id(1) >> prj.children_count => 3 >> prj.children => [] >> prj.all_children => [] 2. I would like to have multiple roots so that I'm not managing one huge tree. I have been trying to use scope to build multiple roots, but haven't had much luck. In the end, I'm assuming that my table should look something like this: id | parent_id | lft | rgt | name ------------------------------------------------------- 1 | | | | ruby 2 | | | | rails 3 | | 1 | 6 | computers 4 | 3 | 2 | 3 | apple 5 | 3 | 4 | 5 | dell 6 | | 1 | 8 | rails plug-ins 7 | 6 | 2 | 3 | better_nested_set 8 | | | | frameworks 9 | 6 | 4 | 5 | restful_authentication 10| 6 | 6 | 7 | authorization 11| | | | databases Or This: id | parent_id | lft | rgt | name ------------------------------------------------------- 1 | | 1 | 2 | ruby 2 | | 1 | 2 | rails 3 | | 1 | 6 | computers 4 | 3 | 2 | 3 | apple 5 | 3 | 4 | 5 | dell 6 | | 1 | 8 | rails plug-ins 7 | 6 | 2 | 3 | better_nested_set 8 | | 1 | 2 | frameworks 9 | 6 | 4 | 5 | restful_authentication 10| 6 | 6 | 7 | authorization 11| | 1 | 2 | databases Here is my code, hopefully this will help identify the problem(s): Migration: class CreateProjects < ActiveRecord::Migration def self.up create_table :projects do |t| t.column :parent_id, :bigint t.column :lft, :integer t.column :rgt, :integer t.column :name, :string end end def self.down drop_table :projects end end Model: class Project < ActiveRecord::Base acts_as_nested_set :order => "name", :scope => :parent_id end Thanks! --Nick From dontfall at gmail.com Wed Dec 27 18:33:56 2006 From: dontfall at gmail.com (Krishna Dole) Date: Wed, 27 Dec 2006 18:33:56 -0500 Subject: [Betternestedset-talk] A couple of questions In-Reply-To: References: Message-ID: <8d64b97d0612271533k13336ba3u6c1e449966f5ada5@mail.gmail.com> Hi Nick, I was wondering how you were getting on-- glad to hear you haven't given up yet! > 1. When I try to get the children of the root object, I'm able to > count them but don't get any return values for children, all_children, > etc. See the comments about scope below. > 2. I would like to have multiple roots so that I'm not managing one > huge tree. I have been trying to use scope to build multiple roots, > but haven't had much luck. In the end, I'm assuming that my table > should look something like this: > It should look like this (your second example), except note the 'root_id' column, which will serve as the scope: > > id | root_id | parent_id | lft | rgt | name > ----------------------------------------------------------------- > 1 | 1 | | 1 | 2 | ruby > 2 | 2 | | 1 | 2 | rails > 3 | 3 | | 1 | 6 | computers > 4 | 3 | 3 | 2 | 3 | apple > 5 | 3 | 3 | 4 | 5 | dell > 6 | 6 | | 1 | 8 | rails plug-ins > 7 | 6 | 6 | 2 | 3 | better_nested_set > 8 | 8 | | 1 | 2 | frameworks > 9 | 6 | 6 | 4 | 5 | restful_authentication > 10| 6 | 6 | 6 | 7 | authorization > 11| 11 | | 1 | 2 | databases > > You don't need to use root_id as your scope, but it is convenient. > acts_as_nested_set :order => "name", :scope => :parent_id Aha! This won't work, and is likely causing your problems. As I mentioned in a previous email, all items in a tree must share the same scope value. Just change it to ':scope => :root_id', make sure the root_id values get set for your records, and you should be on your way. Going through this with you is informative for me, because it makes me aware of the parts of the API that are cryptic and confusing. Cheers, Krishna From linicks at gmail.com Thu Dec 28 13:42:00 2006 From: linicks at gmail.com (Nick Pavlica) Date: Thu, 28 Dec 2006 11:42:00 -0700 Subject: [Betternestedset-talk] A couple of questions In-Reply-To: <8d64b97d0612271533k13336ba3u6c1e449966f5ada5@mail.gmail.com> References: <8d64b97d0612271533k13336ba3u6c1e449966f5ada5@mail.gmail.com> Message-ID: Hi Krishna, > I was wondering how you were getting on-- glad to hear you haven't given up yet! I took a couple of days off for Christmas which took me away from having fun with Ruby/ROR. It's important for me to try and get as many things right with this application as I can so that I have less pain down the road. I think that using nested sets + multiple roots is a very good solution for my application and is worth the effort. > > 1. When I try to get the children of the root object, I'm able to > > count them but don't get any return values for children, all_children, > > etc. > > See the comments about scope below. Changing the scope did fix this problem. > > 2. I would like to have multiple roots so that I'm not managing one > > huge tree. I have been trying to use scope to build multiple roots, > > but haven't had much luck. In the end, I'm assuming that my table > > should look something like this: > > > > It should look like this (your second example), except note the > 'root_id' column, which will serve as the scope: > > > > id | root_id | parent_id | lft | rgt | name > > ----------------------------------------------------------------- > > 1 | 1 | | 1 | 2 | ruby > > 2 | 2 | | 1 | 2 | rails > > 3 | 3 | | 1 | 6 | computers > > 4 | 3 | 3 | 2 | 3 | apple > > 5 | 3 | 3 | 4 | 5 | dell > > 6 | 6 | | 1 | 8 | rails plug-ins > > 7 | 6 | 6 | 2 | 3 | better_nested_set > > 8 | 8 | | 1 | 2 | frameworks > > 9 | 6 | 6 | 4 | 5 | restful_authentication > > 10| 6 | 6 | 6 | 7 | authorization > > 11| 11 | | 1 | 2 | databases > > > > > > You don't need to use root_id as your scope, but it is convenient. > > > acts_as_nested_set :order => "name", :scope => :parent_id > > Aha! This won't work, and is likely causing your problems. This was causing the problems, and in hindsight it makes sense that this would break things. >As I mentioned in a previous email, all items in a tree must share the same > scope value. Just change it to ':scope => :root_id', make sure the > root_id values get set for your records, and you should be on your > way. I added the root_id column to my table and changed scope to ':scope => :root_id', but I'm not sure how to set the root_id values. From the docs, I was thinking that the root_id value would be set when a new record was created without children, and that any children would automatically set their root_id value to it's parents root_id value. However, after making these changes when I create new records no root_id values are set, and all the records are still acting as one tree. >From Docs: "root - root item of the tree (the one that has a nil parent; should have left_column = 1 too)" How are root_id values set? > Going through this with you is informative for me, because it makes me > aware of the parts of the API that are cryptic and confusing. This has been/is a fun growth experience for me, and I hope that others will find the information in these threads helpful when trying to solve there problems. I think that adding some more examples to the documentation, and possibly an example application may help new users work through things. I would be happy help where I can. Thanks! --Nick From dontfall at gmail.com Thu Dec 28 14:46:38 2006 From: dontfall at gmail.com (Krishna Dole) Date: Thu, 28 Dec 2006 14:46:38 -0500 Subject: [Betternestedset-talk] A couple of questions In-Reply-To: References: <8d64b97d0612271533k13336ba3u6c1e449966f5ada5@mail.gmail.com> Message-ID: <8d64b97d0612281146i300d326di97a7d1028ac476d3@mail.gmail.com> Hi Nick, > I took a couple of days off for Christmas which took me away from Shame on you! ;) > I added the root_id column to my table and changed scope to ':scope > => :root_id', but I'm not sure how to set the root_id values. From > the docs, I was thinking that the root_id value would be set when a > new record was created without children, and that any children would > automatically set their root_id value to it's parents root_id value. > However, after making these changes when I create new records no > root_id values are set, and all the records are still acting as one > tree. At the moment it is up to the programmer. Whenever you create objects just do something like this: def create_subproject @project = Project.new(params[:project]) if @project.save if params[:parent_id].empty? # this project has no parent, so it is the root of a new tree @project.update_attribute("root_id", @project.id) else @parent = (params[:parent_id]) @project.update_attribute("root_id", @parent.root_id) @project.move_to_child_of @parent end flash[:notice] = 'Project was successfully created.' redirect_to :action => 'list' else render :action => 'new' end end We could automatically set it, but only if we limited what can be used as a scope. Any thoughts on this, JCM? > This has been/is a fun growth experience for me, and I hope that > others will find the information in these threads helpful when trying > to solve there problems. I think that adding some more examples to > the documentation, and possibly an example application may help new > users work through things. I would be happy help where I can. Yeah, I think more examples would be good. I'm in the midst of a bunch of changes to the nested set API, but after things settle out I'll look at that. best, Krishna From linicks at gmail.com Thu Dec 28 20:24:50 2006 From: linicks at gmail.com (Nick Pavlica) Date: Thu, 28 Dec 2006 18:24:50 -0700 Subject: [Betternestedset-talk] A couple of questions In-Reply-To: <8d64b97d0612281146i300d326di97a7d1028ac476d3@mail.gmail.com> References: <8d64b97d0612271533k13336ba3u6c1e449966f5ada5@mail.gmail.com> <8d64b97d0612281146i300d326di97a7d1028ac476d3@mail.gmail.com> Message-ID: Krishna, I'm starting to make some real progress. I now have multiple trees, but I'm getting this error when I try to create a child: ### Error Begin ##### Impossible move, target node cannot be inside moved tree. #{RAILS_ROOT}/vendor/plugins/betternestedset/lib/better_nested_set.rb:438:in `move_to' #{RAILS_ROOT}/vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:59:in `transaction' #{RAILS_ROOT}/vendor/rails/activerecord/lib/active_record/transactions.rb:95:in `transaction' #{RAILS_ROOT}/vendor/rails/activerecord/lib/active_record/transactions.rb:121:in `transaction' #{RAILS_ROOT}/vendor/plugins/betternestedset/lib/better_nested_set.rb:429:in `move_to' #{RAILS_ROOT}/vendor/plugins/betternestedset/lib/better_nested_set.rb:421:in `move_to_child_of' #{RAILS_ROOT}/app/controllers/project_controller.rb:68:in `create' ### Error End #### Here is my current create method: def create @project = Project.new(params[:project]) @parent = (params[:parent_id]) @root = (params[:root_id]) #breakpoint() if @project.save if not @parent # this project has no parent, so it is the root of a new tree @project.update_attribute("root_id", @project.id) else @project.update_attribute("root_id", @root) @project.move_to_child_of @parent end flash[:notice] = 'Project was successfully created.' redirect_to :action => 'list' else render :action => 'new' end end Thanks! --Nick From dontfall at gmail.com Fri Dec 29 10:05:55 2006 From: dontfall at gmail.com (Krishna Dole) Date: Fri, 29 Dec 2006 10:05:55 -0500 Subject: [Betternestedset-talk] A couple of questions In-Reply-To: References: <8d64b97d0612271533k13336ba3u6c1e449966f5ada5@mail.gmail.com> <8d64b97d0612281146i300d326di97a7d1028ac476d3@mail.gmail.com> Message-ID: <8d64b97d0612290705tedf4e9fy4682d48ebd920440@mail.gmail.com> > def create > @project = Project.new(params[:project]) > @parent = (params[:parent_id]) > @root = (params[:root_id]) > #breakpoint() > if @project.save > if not @parent off the top of my head, if params[:parent_id] is "", it will still evaluate to true. try @parent.empty? instead. > # this project has no parent, so it is the root of a new tree > @project.update_attribute("root_id", @project.id) > else > @project.update_attribute("root_id", @root) > @project.move_to_child_of @parent > end > flash[:notice] = 'Project was successfully created.' > redirect_to :action => 'list' > else > render :action => 'new' > end > end > > > Thanks! > --Nick > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > From linicks at gmail.com Fri Dec 29 12:50:16 2006 From: linicks at gmail.com (Nick Pavlica) Date: Fri, 29 Dec 2006 10:50:16 -0700 Subject: [Betternestedset-talk] A couple of questions In-Reply-To: <8d64b97d0612290705tedf4e9fy4682d48ebd920440@mail.gmail.com> References: <8d64b97d0612271533k13336ba3u6c1e449966f5ada5@mail.gmail.com> <8d64b97d0612281146i300d326di97a7d1028ac476d3@mail.gmail.com> <8d64b97d0612290705tedf4e9fy4682d48ebd920440@mail.gmail.com> Message-ID: Hi Krishna, > > if @project.save > > if not @parent > > off the top of my head, if params[:parent_id] is "", it will still > evaluate to true. When I try: if @parent.empty? instead of: if not @parent I get this exception: You have a nil object when you didn't expect it! You might have expected an instance of Array. The error occurred while evaluating nil.empty? When I use "if not @parent" I'm taken through the control structure to the else statement. else @project.update_attribute("root_id", @root) @project.move_to_child_of @parent end I set some breakpoints right before @project.move_to_child_0f @parent, and everything seemed fine. When I step to that line I get this exception: "Impossible move, target node cannot be inside moved tree." #{RAILS_ROOT}/vendor/plugins/betternestedset/lib/better_nested_set.rb:438:in `move_to' #{RAILS_ROOT}/vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:59:in `transaction' #{RAILS_ROOT}/vendor/rails/activerecord/lib/active_record/transactions.rb:95:in `transaction' #{RAILS_ROOT}/vendor/rails/activerecord/lib/active_record/transactions.rb:121:in `transaction' #{RAILS_ROOT}/vendor/plugins/betternestedset/lib/better_nested_set.rb:429:in `move_to' #{RAILS_ROOT}/vendor/plugins/betternestedset/lib/better_nested_set.rb:421:in `move_to_child_of' #{RAILS_ROOT}/app/controllers/project_controller.rb:65:in `create' /usr/bin/mongrel_rails:18 Essentially, I'm able to crate root projects all day long with out issue. When I try to make a record a child, I get the exception noted above. However, a record is still created with all of the expected root attributes. 1) Create a root project with no exceptions: id | root_id | parent_id| lft | rgt | name 1 | 1 | | 1 | 2 | Root Project 2) I then try to add a sub project by passing it a parent_id value. Then get the can't move exception. 2 | 1 | | 1 | 2 | Sub Project Notice that the root ID (1) is correct, but there is no parent, which should also be 1. Here is the plug-in code that handles this exception: # detect impossible move if ((cur_left <= target_left) && (target_left <= cur_right)) or ((cur_left <= target_right) && target_right <= cur_right)) raise ActiveRecord::ActiveRecordError, "Impossible move, target node cannot be inside moved tree." end Looking at the exception logic, It would seem that all the conditions are meet to throw the exception. I'm not sure how to change the behavior of the create method such that this exception would be avoided. Many Thanks! --Nick From dontfall at gmail.com Fri Dec 29 13:22:35 2006 From: dontfall at gmail.com (Krishna Dole) Date: Fri, 29 Dec 2006 13:22:35 -0500 Subject: [Betternestedset-talk] A couple of questions In-Reply-To: References: <8d64b97d0612271533k13336ba3u6c1e449966f5ada5@mail.gmail.com> <8d64b97d0612281146i300d326di97a7d1028ac476d3@mail.gmail.com> <8d64b97d0612290705tedf4e9fy4682d48ebd920440@mail.gmail.com> Message-ID: <8d64b97d0612291022o251b56ben10493300a31cfbcd@mail.gmail.com> Hi Nick, > 1) Create a root project with no exceptions: > > id | root_id | parent_id| lft | rgt | name > 1 | 1 | | 1 | 2 | Root Project > > 2) I then try to add a sub project by passing it a parent_id value. > Then get the can't move exception. > > 2 | 1 | | 1 | 2 | Sub Project Ah! The previous create method I sent you was wrong. The problem was that it set the root_id for sub-projects after they had been created, but by that time the lft/rgt values were wrong (they should have been 3 and 4). Try this: def create @project = Project.new(params[:project]) @parent = (params[:parent_id]) @root = (params[:root_id]) if @parent # this must be done before save, otherwise a new tree would be created # (because root_id would be NULL, which would be different than existing trees) @project.root_id = @root end if @project.save if not @parent # this project has no parent, so it is the root of a new tree @project.update_attribute("root_id", @project.id) else @project.move_to_child_of @parent end flash[:notice] = 'Project was successfully created.' redirect_to :action => 'list' else render :action => 'new' end end From dontfall at gmail.com Fri Dec 29 15:12:14 2006 From: dontfall at gmail.com (Krishna Dole) Date: Fri, 29 Dec 2006 15:12:14 -0500 Subject: [Betternestedset-talk] Exciting(?) changes to BetterNestedSet Message-ID: <8d64b97d0612291212u40bd20a5t4d66d00a98b9a1a7@mail.gmail.com> Hi Everyone, For about a year I have wanted to write a nested set implementation that was as easy to use as acts_as_tree. Using BetterNestedSet I've taken my first shot at that. The idea is fairly simple: the model belongs_to :parent and has_many :children, and an after_save callback takes care of updating the left/right values. You can still use move_to_child_of, but you don't need to: s = Set.new s.children.create # adds a child and saves it s.children << Set.new # add another child s.save # the child is saved to the database s2 = Set.new s.parent= s2 s.save s2.parent.create The tree would now look like this, and all the left/right values would be correct: root s2 s child1 child2 All of the other has_many and belongs_to methods are available as well, such as #children.delete(child), #children = [c1, ...], etc. This version of BetterNestedSet currently exists as a branch, so if you want to play with it: script/plugin install svn://rubyforge.org/var/svn/betternestedset/branches/ez-set I'm quite curious to hear what everyone thinks of this. It is pretty well tested, but could certainly use some real-world exposure. FYI, it does not have any of the deprecated methods. I haven't updated the documentation yet. The trunk line of BetterNestedSet has been active as well. Aside from bug fixes, here's a summary of the externally visible changes I've made since mid-November: - Renamed #children_count to #all_children_count (the old name was both misleading, inconsistent with other methods, and inconsistent with acts_as_tree) - Changed #move_to_child_of so it inserts children on the right. - Added class method #sql_for, wich generates an SQL fragment for use in queries - Documentation overhaul. - Made all left/right altering methods concurrency-safe by using transactions, calling object.reload, and by overriding ActiveRecord's #update. - Fixed STI problem (http://opensource.symetrie.com/trac/better_nested_set/ticket/10) - Added scope enforcement for the move_to* methods (to prevent moving nodes between different trees). - Added methods to return or count leaf nodes (terminal children). - Added methods to re-index trees (for converting standard trees to nested sets, or repairing corrupted lft/rgt indexes). - Lots and lots of tests. Cheers, Krishna From linicks at gmail.com Fri Dec 29 18:55:27 2006 From: linicks at gmail.com (Nick Pavlica) Date: Fri, 29 Dec 2006 16:55:27 -0700 Subject: [Betternestedset-talk] A couple of questions In-Reply-To: <8d64b97d0612291022o251b56ben10493300a31cfbcd@mail.gmail.com> References: <8d64b97d0612271533k13336ba3u6c1e449966f5ada5@mail.gmail.com> <8d64b97d0612281146i300d326di97a7d1028ac476d3@mail.gmail.com> <8d64b97d0612290705tedf4e9fy4682d48ebd920440@mail.gmail.com> <8d64b97d0612291022o251b56ben10493300a31cfbcd@mail.gmail.com> Message-ID: Krishna, The last set of changes seems to be working perfectly. Thanks for helping me work through this! I have been doing the happy dance for about twenty minutes :) > We could automatically set it, but only if we limited what can be used > as a scope. Any thoughts on this, JCM? What if you did something like this ? acts_as_nested_set :root_scope => :root_id I noticed your announcement regarding the changes to the plug-in. Would you recommend moving to the new branch, or hold off for now? Thanks Again!!!! -Nick From linicks at gmail.com Sat Dec 30 10:53:43 2006 From: linicks at gmail.com (Nick Pavlica) Date: Sat, 30 Dec 2006 08:53:43 -0700 Subject: [Betternestedset-talk] Exciting(?) changes to BetterNestedSet In-Reply-To: <8d64b97d0612291212u40bd20a5t4d66d00a98b9a1a7@mail.gmail.com> References: <8d64b97d0612291212u40bd20a5t4d66d00a98b9a1a7@mail.gmail.com> Message-ID: Krishna, This looks like a excellent continuation of the great work that you have been doing with better_nested_sets. I was curious if this new branch would become a fork(ez-set), or if it would become the next version of better_nested_sets ? --Nick From dontfall at gmail.com Sat Dec 30 11:40:13 2006 From: dontfall at gmail.com (Krishna Dole) Date: Sat, 30 Dec 2006 11:40:13 -0500 Subject: [Betternestedset-talk] A couple of questions In-Reply-To: References: <8d64b97d0612271533k13336ba3u6c1e449966f5ada5@mail.gmail.com> <8d64b97d0612281146i300d326di97a7d1028ac476d3@mail.gmail.com> <8d64b97d0612290705tedf4e9fy4682d48ebd920440@mail.gmail.com> <8d64b97d0612291022o251b56ben10493300a31cfbcd@mail.gmail.com> Message-ID: <8d64b97d0612300840j45de37ffw363dd6062f2e5512@mail.gmail.com> Hi Nick, Glad to hear things are working. > acts_as_nested_set :root_scope => :root_id The problem is that if you have multiple trees, each with multiple roots, the code wouldn't know if a new record without a parent should be saved with a scope that would make it part of an existing tree or the root of a new tree. If we discarded the multiple root option, we could make it work. > I noticed your announcement regarding the changes to the plug-in. > Would you recommend moving to the new branch, or hold off for now? If you have things working the way you want, there isn't really any reason to switch. Cheers, k From dontfall at gmail.com Sat Dec 30 11:46:53 2006 From: dontfall at gmail.com (Krishna Dole) Date: Sat, 30 Dec 2006 11:46:53 -0500 Subject: [Betternestedset-talk] Exciting(?) changes to BetterNestedSet In-Reply-To: References: <8d64b97d0612291212u40bd20a5t4d66d00a98b9a1a7@mail.gmail.com> Message-ID: <8d64b97d0612300846j13b1f2eekee509c21bfc0d252@mail.gmail.com> I would favor merging the changes into trunk at some point, but only if JCM and others agree. Right now it is just a new approach for people to test and think about. k On 12/30/06, Nick Pavlica wrote: > Krishna, > This looks like a excellent continuation of the great work that you > have been doing with better_nested_sets. I was curious if this new > branch would become a fork(ez-set), or if it would become the next > version of better_nested_sets ? > > --Nick > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > From mhe_mailing at gmx.de Sat Dec 30 18:33:04 2006 From: mhe_mailing at gmx.de (Matthias Heigl) Date: Sun, 31 Dec 2006 00:33:04 +0100 Subject: [Betternestedset-talk] before_update problem Message-ID: <20061230233304.142010@gmx.net> Hi List, first of all i introduce myself. I am a fairly ror-newbie, with 2 week experience on it. I'm developing a departent-management application with one STI-Table. Issue < ActiveRecord::Base Project < Issue Milestone < Project Task < Milestone Because of the STI problem in acts_as_nested_set i found betternestedset and used it. Now i have a problem. It seems that before_update callback doesn't work anymore. First i wondered why my magic field updated_at didn't get updated when i edit any Project, Milestone or Task. Then for tests i added the following to my model issue.rb - - - - - - before_update :update_fields before_create :update_create private def update_fields logger.info "--- issue: before update ---" end def update_create logger.info "--- issue: before create ---" end - - - - - - In my log only the before_create on create appears but never the before_update on updates. A quick test, im really not shure, with normal acts_as_nested_set and only on Issue, because of the STI problem, everything was ok. Another issue i recognized is that the before_create callback is executed three times with betternestedset/acts_as_nested_set. This could be a performance issue in certain circumstances. I hope there is a solution, because i need the before_update callback of some other reasons. Cheers, Matze From dontfall at gmail.com Sat Dec 30 23:51:18 2006 From: dontfall at gmail.com (Krishna Dole) Date: Sat, 30 Dec 2006 23:51:18 -0500 Subject: [Betternestedset-talk] before_update problem In-Reply-To: <20061230233304.142010@gmx.net> References: <20061230233304.142010@gmx.net> Message-ID: <8d64b97d0612302051gcd776cfye0fdee32d8a37e35@mail.gmail.com> Hi Matze, Thanks for letting us know about this. I'll certainly look into it, but it might not be for a few days. Krishna On 12/30/06, Matthias Heigl wrote: > Hi List, > > first of all i introduce myself. > > I am a fairly ror-newbie, with 2 week experience on it. I'm developing a departent-management application with one STI-Table. > > Issue < ActiveRecord::Base > Project < Issue > Milestone < Project > Task < Milestone > > Because of the STI problem in acts_as_nested_set i found betternestedset and used it. Now i have a problem. It seems that before_update callback doesn't work anymore. > > First i wondered why my magic field updated_at didn't get updated when i edit any Project, Milestone or Task. Then for tests i added the following to my model issue.rb > > - - - - - - > before_update :update_fields > before_create :update_create > private > > def update_fields > logger.info "--- issue: before update ---" > end > > def update_create > logger.info "--- issue: before create ---" > end > - - - - - - > > In my log only the before_create on create appears but never the before_update on updates. > > A quick test, im really not shure, with normal acts_as_nested_set and only on Issue, because of the STI problem, everything was ok. > > Another issue i recognized is that the before_create callback is executed three times with betternestedset/acts_as_nested_set. This could be a performance issue in certain circumstances. > > I hope there is a solution, because i need the before_update callback of some other reasons. > > Cheers, > > Matze > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk > From mhe_mailing at gmx.de Sun Dec 31 09:19:23 2006 From: mhe_mailing at gmx.de (Matthias Heigl) Date: Sun, 31 Dec 2006 15:19:23 +0100 Subject: [Betternestedset-talk] before_update problem In-Reply-To: <8d64b97d0612302051gcd776cfye0fdee32d8a37e35@mail.gmail.com> References: <20061230233304.142010@gmx.net> <8d64b97d0612302051gcd776cfye0fdee32d8a37e35@mail.gmail.com> Message-ID: <20061231141923.19650@gmx.net> Hi Krishna, after a bit sleep i made a clean test, maybe my other code could cause this problem. So i set up a clean acts_as_nested_set. My migration - - - - - class CreateItems < ActiveRecord::Migration def self.up create_table :items do |t| # acts_as_nested_set colums t.column :parent_id, :integer t.column :lft, :integer t.column :rgt, :integer # common attributes t.column :name, :string end end ... - - - - - my model item.rb - - - - - class Item < ActiveRecord::Base acts_as_nested_set before_update :update_fields before_create :update_create private def update_fields logger.info "--- item: before update ---" logger.info "#{self.name} - #{self}" end def update_create logger.info "--- item: before create ---" logger.info "#{self.name} - #{self}" end end - - - - - created a clean scaffold on this and added in items_controller.rb - - - - - ... def add @item = Item.new @item.parent_id = params[:id] render :action => 'new' end def create @item = Item.new(params[:item]) if @item.parent_id.to_i > 0 parent = Item.find(@item.parent_id) if @item.save parent.add_child(@item) flash[:notice] = 'Item was successfully added.' redirect_to :action => 'list' end else if @item.save flash[:notice] = 'Item was successfully created.' redirect_to :action => 'list' else render :action => 'new' end end end ... - - - - - remark: i know it's ugly but for a quick test it will be ok. _form.rhtml added - - - - - Parent: <%= text_field 'item', 'parent_id' %> - - - - - here goes my steps an log: - - - - - 1. add "new item" Processing ItemsController#create (for 127.0.0.1 at 2006-12-31 14:43:50) [POST] Session ID: 9e719642e8a39389a8386344d6c4fc96 Parameters: {"commit"=>"Create", "action"=>"create", "controller"=>"items", "item"=>{"name"=>"new item", "lft"=>"", "rgt"=>"", "parent_id"=>""}} Item Columns (0.010000) SHOW FIELDS FROM items SQL (0.000000) BEGIN --- item: before create --- new item - # SQL (0.000000) INSERT INTO items (`name`, `lft`, `type`, `parent_id`, `rgt`) VALUES('new item', NULL, NULL, NULL, NULL) SQL (0.000000) COMMIT Redirected to http://localhost:3000/items/list Completed in 0.04000 (25 reqs/sec) | DB: 0.01000 (25%) | 302 Found [http://localhost/items/create] 2. edit "new item" Processing ItemsController#update (for 127.0.0.1 at 2006-12-31 14:45:39) [POST] Session ID: 9e719642e8a39389a8386344d6c4fc96 Parameters: {"commit"=>"Edit", "action"=>"update", "id"=>"8", "controller"=>"items", "item"=>{"name"=>"new item - edit", "lft"=>"", "rgt"=>"", "parent_id"=>""}} Item Columns (0.000000) SHOW FIELDS FROM items Item Load (0.000000) SELECT * FROM items WHERE (items.id = 8) SQL (0.000000) BEGIN --- item: before update --- new item - edit - # Item Update (0.000000) UPDATE items SET `rgt` = NULL, `type` = NULL, `lft` = NULL, `parent_id` = NULL, `name` = 'new item - edit' WHERE id = 8 SQL (0.000000) COMMIT Redirected to http://localhost:3000/items/show/8 Completed in 0.05000 (20 reqs/sec) | DB: 0.00000 (0%) | 302 Found [http://localhost/items/update/8] 3. add_child "child item" to "new item - edit" Processing ItemsController#create (for 127.0.0.1 at 2006-12-31 14:46:35) [POST] Session ID: 9e719642e8a39389a8386344d6c4fc96 Parameters: {"commit"=>"Create", "action"=>"create", "controller"=>"items", "item"=>{"name"=>"child item", "lft"=>"", "rgt"=>"", "parent_id"=>"8"}} Item Columns (0.000000) SHOW FIELDS FROM items Item Load (0.000000) SELECT * FROM items WHERE (items.id = 8) SQL (0.000000) BEGIN --- item: before create --- child item - # SQL (0.000000) INSERT INTO items (`name`, `lft`, `type`, `parent_id`, `rgt`) VALUES('child item', NULL, NULL, 8, NULL) SQL (0.000000) COMMIT Item Load (0.000000) SELECT * FROM items WHERE (items.id = 8) Item Load (0.000000) SELECT * FROM items WHERE (items.id = 9) SQL (0.000000) BEGIN --- item: before update --- new item - edit - # Item Update (0.000000) UPDATE items SET `rgt` = 4, `type` = NULL, `lft` = 1, `parent_id` = NULL, `name` = 'new item - edit' WHERE id = 8 SQL (0.000000) COMMIT SQL (0.000000) BEGIN --- item: before update --- child item - # Item Update (0.000000) UPDATE items SET `rgt` = 3, `type` = NULL, `lft` = 2, `parent_id` = 8, `name` = 'child item' WHERE id = 9 SQL (0.000000) COMMIT Redirected to http://localhost:3000/items/list Completed in 0.07000 (14 reqs/sec) | DB: 0.00000 (0%) | 302 Found [http://localhost/items/create] 4. edit "child item" Processing ItemsController#update (for 127.0.0.1 at 2006-12-31 14:47:39) [POST] Session ID: 9e719642e8a39389a8386344d6c4fc96 Parameters: {"commit"=>"Edit", "action"=>"update", "id"=>"9", "controller"=>"items", "item"=>{"name"=>"child item - edit", "lft"=>"2", "rgt"=>"3", "parent_id"=>"8"}} Item Columns (0.010000) SHOW FIELDS FROM items Item Load (0.000000) SELECT * FROM items WHERE (items.id = 9) SQL (0.000000) BEGIN --- item: before update --- child item - edit - # Item Update (0.000000) UPDATE items SET `rgt` = 3, `type` = NULL, `lft` = 2, `parent_id` = 8, `name` = 'child item - edit' WHERE id = 9 SQL (0.000000) COMMIT Redirected to http://localhost:3000/items/show/9 Completed in 0.04000 (25 reqs/sec) | DB: 0.01000 (25%) | 302 Found [http://localhost/items/update/9] - - - - - After that i added betternestedset to vendor/plugins. Because of "Unauthorized assignment to parent_id: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead." i hardcoded the parent id in the controller. For this test it seems ok to me. - - - - - ... def reply @item = Item.new #@item.parent_id = params[:id] render :action => 'new' end def create @item = Item.new(params[:item]) if true parent = Item.find(1) if @item.save @item.move_to_child_of parent flash[:notice] = 'Item was successfully added.' redirect_to :action => 'list' end else if @item.save flash[:notice] = 'Item was successfully created.' redirect_to :action => 'list' else render :action => 'new' end end end ... - - - - - here goes my steps and log 1. add "new item" Processing ItemsController#create (for 127.0.0.1 at 2006-12-31 14:52:41) [POST] Session ID: 9e719642e8a39389a8386344d6c4fc96 Parameters: {"commit"=>"Create", "action"=>"create", "controller"=>"items", "item"=>{"name"=>"new item", "lft"=>"", "rgt"=>"", "parent_id"=>""}} Item Columns (0.000000) SHOW FIELDS FROM items SQL (0.000000) BEGIN --- item: before create --- new item - # SQL (0.000000) SELECT max(rgt) AS max_rgt FROM items WHERE (1 = 1) SQL (0.000000) INSERT INTO items (`name`, `lft`, `type`, `parent_id`, `rgt`) VALUES('new item', 1, NULL, NULL, 2) SQL (0.000000) COMMIT Redirected to http://localhost:3000/items/list Completed in 0.04000 (25 reqs/sec) | DB: 0.00000 (0%) | 302 Found [http://localhost/items/create] 2. edit "new item" Processing ItemsController#update (for 127.0.0.1 at 2006-12-31 14:53:13) [POST] Session ID: 9e719642e8a39389a8386344d6c4fc96 Parameters: {"commit"=>"Edit", "action"=>"update", "id"=>"1", "controller"=>"items", "item"=>{"name"=>"new item - edit", "lft"=>"1", "rgt"=>"2", "parent_id"=>""}} Item Columns (0.000000) SHOW FIELDS FROM items Item Load (0.000000) SELECT * FROM items WHERE (items.id = 1) SQL (0.000000) BEGIN Item Update (0.000000) UPDATE items SET `type` = NULL, `parent_id` = NULL, `name` = 'new item - edit' WHERE id = 1 SQL (0.000000) COMMIT Redirected to http://localhost:3000/items/show/1 Completed in 0.09000 (11 reqs/sec) | DB: 0.00000 (0%) | 302 Found [http://localhost/items/update/1] 3. add "child item" and move_to_child_of "new item - edit" Processing ItemsController#create (for 127.0.0.1 at 2006-12-31 14:55:21) [POST] Session ID: 9e719642e8a39389a8386344d6c4fc96 Parameters: {"commit"=>"Create", "action"=>"create", "controller"=>"items", "item"=>{"name"=>"child item", "lft"=>"", "rgt"=>"", "parent_id"=>""}} Item Columns (0.000000) SHOW FIELDS FROM items Item Load (0.000000) SELECT * FROM items WHERE (items.id = 1) SQL (0.000000) BEGIN --- item: before create --- child item - # SQL (0.000000) SELECT max(rgt) AS max_rgt FROM items WHERE (1 = 1) SQL (0.000000) INSERT INTO items (`name`, `lft`, `type`, `parent_id`, `rgt`) VALUES('child item', 3, NULL, NULL, 4) SQL (0.010000) COMMIT SQL (0.000000) BEGIN Item Load (0.000000) SELECT * FROM items WHERE (items.id = 2) Item Load (0.000000) SELECT * FROM items WHERE (items.id = 1) Item Update (0.010000) UPDATE items SET lft = CASE WHEN lft BETWEEN 2 AND 2 THEN lft + 2 WHEN lft BETWEEN 3 AND 4 THEN lft + -1 ELSE lft END, rgt = CASE WHEN rgt BETWEEN 2 AND 2 THEN rgt + 2 WHEN rgt BETWEEN 3 AND 4 THEN rgt + -1 ELSE rgt END, parent_id = CASE WHEN id = 2 THEN 1 ELSE parent_id END WHERE (1 = 1) Item Load (0.000000) SELECT * FROM items WHERE (items.id = 2) Item Load (0.000000) SELECT * FROM items WHERE (items.id = 1) SQL (0.010000) COMMIT Redirected to http://localhost:3000/items/list Completed in 0.07000 (14 reqs/sec) | DB: 0.03000 (42%) | 302 Found [http://localhost/items/create] 4. edit "child item" Processing ItemsController#update (for 127.0.0.1 at 2006-12-31 14:56:08) [POST] Session ID: 9e719642e8a39389a8386344d6c4fc96 Parameters: {"commit"=>"Edit", "action"=>"update", "id"=>"2", "controller"=>"items", "item"=>{"name"=>"child item - edit", "lft"=>"2", "rgt"=>"3", "parent_id"=>"1"}} Item Columns (0.000000) SHOW FIELDS FROM items Item Load (0.000000) SELECT * FROM items WHERE (items.id = 2) SQL (0.000000) BEGIN Item Update (0.000000) UPDATE items SET `type` = NULL, `parent_id` = 1, `name` = 'child item - edit' WHERE id = 2 SQL (0.000000) COMMIT Redirected to http://localhost:3000/items/show/2 Completed in 0.04000 (25 reqs/sec) | DB: 0.00000 (0%) | 302 Found [http://localhost/items/update/2] - - - - - As you can see, after adding betternestedset no more before_update callback is executed. I hope this is helpful. And happy New Years Eve Everyone! Cheers, Matze -------- Original-Nachricht -------- Datum: Sat, 30 Dec 2006 23:51:18 -0500 Von: "Krishna Dole" An: betternestedset-talk at rubyforge.org Betreff: Re: [Betternestedset-talk] before_update problem > Hi Matze, > > Thanks for letting us know about this. I'll certainly look into it, > but it might not be for a few days. > > Krishna > > On 12/30/06, Matthias Heigl wrote: > > Hi List, > > > > first of all i introduce myself. > > > > I am a fairly ror-newbie, with 2 week experience on it. I'm developing a > departent-management application with one STI-Table. > > > > Issue < ActiveRecord::Base > > Project < Issue > > Milestone < Project > > Task < Milestone > > > > Because of the STI problem in acts_as_nested_set i found betternestedset > and used it. Now i have a problem. It seems that before_update callback > doesn't work anymore. > > > > First i wondered why my magic field updated_at didn't get updated when i > edit any Project, Milestone or Task. Then for tests i added the following > to my model issue.rb > > > > - - - - - - > > before_update :update_fields > > before_create :update_create > > private > > > > def update_fields > > logger.info "--- issue: before update ---" > > end > > > > def update_create > > logger.info "--- issue: before create ---" > > end > > - - - - - - > > > > In my log only the before_create on create appears but never the > before_update on updates. > > > > A quick test, im really not shure, with normal acts_as_nested_set and > only on Issue, because of the STI problem, everything was ok. > > > > Another issue i recognized is that the before_create callback is > executed three times with betternestedset/acts_as_nested_set. This could be a > performance issue in certain circumstances. > > > > I hope there is a solution, because i need the before_update callback of > some other reasons. > > > > Cheers, > > > > Matze > > _______________________________________________ > > Betternestedset-talk mailing list > > Betternestedset-talk at rubyforge.org > > http://rubyforge.org/mailman/listinfo/betternestedset-talk > > > _______________________________________________ > Betternestedset-talk mailing list > Betternestedset-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/betternestedset-talk From jc.michel at symetrie.com Sun Dec 31 05:55:12 2006 From: jc.michel at symetrie.com (Jean-Christophe Michel) Date: Sun, 31 Dec 2006 11:55:12 +0100 Subject: [Betternestedset-talk] Exciting(?) changes to BetterNestedSet In-Reply-To: <8d64b97d0612291212u40bd20a5t4d66d00a98b9a1a7@mail.gmail.com> References: <8d64b97d0612291212u40bd20a5t4d66d00a98b9a1a7@mail.gmail.com> Message-ID: Hi Krishna, Le 29 d?c. 06, ? 21:12, Krishna Dole a ?crit : > For about a year I have wanted to write a nested set implementation > that was as easy to use as acts_as_tree. Using BetterNestedSet I've > taken my first shot at that. The idea is fairly simple: the model > belongs_to :parent and has_many :children, and an after_save callback > takes care of updating the left/right values. You can still use > move_to_child_of, but you don't need to: > > s = Set.new > s.children.create # adds a child and saves it > s.children << Set.new # add another child > s.save # the child is saved to the database > > s2 = Set.new > s.parent= s2 > s.save > > s2.parent.create > > The tree would now look like this, and all the left/right values would > be correct Great work. I'd like to see benchmarks though, since using associations could be slower, don't you think ? Jean-Christophe Michel -- symetrie.com Better Nested Set for rails: http://opensource.symetrie.com/trac/better_nested_set From jc.michel at symetrie.com Sun Dec 31 05:52:01 2006 From: jc.michel at symetrie.com (Jean-Christophe Michel) Date: Sun, 31 Dec 2006 11:52:01 +0100 Subject: [Betternestedset-talk] A couple of questions In-Reply-To: <8d64b97d0612281146i300d326di97a7d1028ac476d3@mail.gmail.com> References: <8d64b97d0612271533k13336ba3u6c1e449966f5ada5@mail.gmail.com> <8d64b97d0612281146i300d326di97a7d1028ac476d3@mail.gmail.com> Message-ID: Hi, Le 28 d?c. 06, ? 20:46, Krishna Dole a ?crit : > At the moment it is up to the programmer. Whenever you create objects > just do something like this: > > def create_subproject > @project = Project.new(params[:project]) > if @project.save > if params[:parent_id].empty? > # this project has no parent, so it is the root of a new tree > @project.update_attribute("root_id", @project.id) > else > @parent = (params[:parent_id]) > @project.update_attribute("root_id", @parent.root_id) > @project.move_to_child_of @parent > end > flash[:notice] = 'Project was successfully created.' > redirect_to :action => 'list' > else > render :action => 'new' > end > end > > We could automatically set it, but only if we limited what can be used > as a scope. Any thoughts on this, JCM? Is there a simple way to achieve this ? like testing :scope ? or an option :inherit_scope_on_creation to explicitely ask to copy scope from parent on creation ? Jean-Christophe Michel -- symetrie.com Better Nested Set for rails: http://opensource.symetrie.com/trac/better_nested_set