collectiveidea / awesome_nested_set Goto Github PK
View Code? Open in Web Editor NEWAn awesome replacement for acts_as_nested_set and better_nested_set.
License: MIT License
An awesome replacement for acts_as_nested_set and better_nested_set.
License: MIT License
Hi there, for some reason some of my customers nested sets have become heavily corrupted. The root node doesn't contain many of the sub-nodes which is causing major havoc. I've just recently converted them from acts_as_tree so I'm not 100% sure when the corruption occurred.
Anyway the damage is done, so I'm just wondering if there are any tools out there that can help fix up problems like this. The only thing I can think of is forcing a rebuild! and ordering by lft just to help maintain the order of objects in the tree. Is there anything else I can do?
Should I upgrade to a later version of awesome nested set? :)
Cheers,
Brendon
Problem:
hash format doesn't seem to play well with strings as keys (at least not in combination w/ other scopes)
Fix:
lib/awesome_nested_set.rb:
def self_and_siblings
nested_set_scope.scoped :conditions => {parent_column_name.to_sym => parent_id}
end
Proof:
c = Comment.first; Comment.find :all, :conditions => {c.parent_column_name.to_sym => c.parent_id}
=> [#<Comment id: 1, title: nil, ...
c = Comment.first; Comment.find :all, :conditions => {c.parent_column_name => c.parent_id}
ActiveRecord::PreparedStatementInvalid: wrong number of bind variables (0 for 1) in:comments
.parent_id
is ?
from vendor/rails/activerecord/lib/active_record/base.rb:2400:in raise_if_bind_arity_mismatch'
I am in the process of converting from betternestedset to awesome_nested_set and am having to create wrappers around methods (specifically move_to_child_of) because update_attributes is proceeding to save the record when move_to_child_of fails.
I have created a wrapper around move_to_child_of to perform validations necessary to determine if the move is legal, and if not returning false. With betternestedset, when the move_to_child_of would return false it would return false to update_attributes to I could raise an error to the user about the change. I am having to write a bunch of extra code ensure that it doesn't allow the saving of a record.
Can you tell me if this is something that is fixable?
Thanks
Brad
This is kind of related to issue #12 by ryanb but different enough I think that it deserves its own ticket.
I have a recursive helper which creates a navigation tree using HAML (with links etc.)
def create_category_tree(category)
haml_tag "ul.navigation" do
haml_tag :li do
haml_tag( :a, category.name, {:href => category_path(category)} )
category.children.each do |child|
create_category_tree(child)
end
end
end
end
Currently when I use it it makes many SQL Calls for the various children. If I use nested :include in the AR finder I can reduce the number of calls, something like
HAML VIEW
- Category.all(:conditions => {:parent_id => nil}, :include => {:children => {:children => :children}}).each do |category|
- create_category_tree(category)
However, this of course doesn't scale depending on the number of children and is ugly as sin and a crime against rails etc.
What I am after is a method that retrieves all the current node and all the children in a standard AR structure so that it can be retrieved with a single SQL call and worked on just like a normal set of AR records.
Is it currently possible to do this? I cannot find anything obvious and ryanb's code doesn't quite do what I would like it to from what I can see.
Cheers
RJ
Given an awesome_nested_set model that's inside a module, trying to fetch the parent of a record raises "ArgumentError: is not missing constant !" For example, with the following model:
class Namespace::NestedFoo < ActiveRecord::Base
acts_as_nested_set
end
the following triggers the bug:
>> root = Namespace::NestedFoo.create
=> #<Namespace::NestedFoo id: 3, parent_id: nil, lft: 1, rgt: 2, created_at: "2009-10-07 03:10:30", updated_at: "2009-10-07 03:10:30">
>> child = Namespace::NestedFoo.create
=> #<Namespace::NestedFoo id: 4, parent_id: nil, lft: 3, rgt: 4, created_at: "2009-10-07 03:10:40", updated_at: "2009-10-07 03:10:40">
>> child.move_to_child_of root
=> []
>> child.parent
ArgumentError: Namespace is not missing constant NestedFoo!
from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:417:in `load_missing_constant'
from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:80:in `const_missing'
from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:98:in `send'
from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:98:in `const_missing'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2197:in `compute_type'
from /Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/core_ext/kernel/reporting.rb:11:in `silence_warnings'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2195:in `compute_type'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/reflection.rb:156:in `send'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/reflection.rb:156:in `klass'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/associations/belongs_to_association.rb:49:in `find_target'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/associations/association_proxy.rb:240:in `load_target'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/associations/association_proxy.rb:112:in `reload'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/associations.rb:1247:in `parent'
from (irb):4
I've forked-and-fixed here: http://github.com/krbullock/awesome_nested_set
I have a class:
class Node < ActiveRecord::Base
acts_as_nested_set :parent_column => "parent_node_uuid"
end
When I verify Node.acts_as_nested_set_options[:parent_column], it outputs my custom column already. But I use Node.rebuild!, I get an error NoMethodError: undefined method `parent_id_changed?'
ag.children
=> []
ag2 = AccountGroup.create({:name => 'System Administrators'})
=> #<AccountGroup id: 173, name: "System Administrators", description: nil, parent_id: nil, lft: 345, rgt: 346, slfgrp: nil, created_at: "2010-02-26 08:56:16", updated_at: "2010-02-26 08:56:16">
ag3 = AccountGroup.create({:name => 'Architecture'})
=> #<AccountGroup id: 174, name: "Architecture", description: nil, parent_id: nil, lft: 347, rgt: 348, slfgrp: nil, created_at: "2010-02-26 08:56:23", updated_at: "2010-02-26 08:56:23">
ag2.move_to_child_of ag
=> []
ag3.move_to_child_of ag
=> []
ag.children
=> [#<AccountGroup id: 174, name: "Architecture", description: nil, parent_id: 172, lft: 344, rgt: 345, slfgrp: nil, created_at: "2010-02-26 08:56:23", updated_at: "2010-02-26 08:56:23">, #<AccountGroup id: 173, name: "System Administrators", description: nil, parent_id: 172, lft: 346, rgt: 347, slfgrp: nil, created_at: "2010-02-26 08:56:16", updated_at: "2010-02-26 08:56:16">]
ag.children.size
=> 2
ag4 = AccountGroup.create({:name => 'Platform Services'})
=> #<AccountGroup id: 175, name: "Platform Services", description: nil, parent_id: nil, lft: 349, rgt: 350, slfgrp: nil, created_at: "2010-02-26 08:58:03", updated_at: "2010-02-26 08:58:03">
ag4.move_to_child_of ag2
=> []
ag.children.size
=> 2
ag.descendants.size
=> 2
** Shouldn't descendants be equal to 3? FTR, when I uninstall awesome_nested_set and install better_nested_set, without changing any of the above records in the DB, 'ag.all_children' returns 3. 'all_children' is the same method as 'descendants' , which I'm sure you already know.
Hello, If I create a new object, it has a lft value of nil. If I try to move that object, I get
NoMethodError: You have a nil object when you didn't expect it!
The error occurred while evaluating nil.<=
which is returned by !((left <= target.left && right >= target.left) or (left <= target.right && right >= target.right)) # (line 410 of awesome_nested_set.rb)
I don't know if a new record should have a default value for lft and rgt. Any idea?
Hi,
I have a requirement to create scope based on two attributes range (using BETWEEN operator). Like table.min_value <= product_id <= table.max_value.
Thank you in advance!
I'm a rails-newbie trying to create multiple root nodes using a_n_s. I wasn't sure whether multiple roots are supported, but methods like "all_roots_valid?()" lead me to suspect so.
When using
<%= f.select :parent_id, nested_set_options(Storage, @storage) {|i| "#{'-' * i.level * 2} #{i.name}" } %>
in my new-view, I can select all existing nodes as parent for my new node. But I just cannot figure out how to create further root-nodes (parent_id=NULL) using this approach, because the generated would have to include a NULL-. How can I do this? Also, I'd prefer to indent children in the selectbox using " " instead of "-", but the html is escaped to " ", so that doesn't work. Any ideas how I could get that working? I hope this is the right forum to ask these kinds of questions. thanks! ben
I've got a simple subject hierarchy, one of my after_create callbacks needs to know the names of all of the ancestors so I can generate a neat name "foo/bar/baz". To do this I was using the self_and_ancestors method. However, on closer inspection this uses a named scope - so will only return values that are already saved in the database, and as each parents left and right columns are updated after the leaf has been saved - it only ever returns it's self.
Now I was thinking of altering the code to detect if it's a new record and fallback to a more recursive method of returning the ancestors but it occurs to me this will cause no end of pain for people who are using self_and_ancestors in a chain of named_scopes.
How would you deal with this?
When trying:
Page.root.children.find_or_create_by_title('contact')
wiil rails an ActiveRecord::RecordNotFound Exception
the break point is in:
def move_to(target, position)
raise ActiveRecord::ActiveRecordError, "You cannot move a new node" if self.new_record?
return if run_callbacks(:before_move) == false
transaction do
if target.is_a? self.class.base_class
target.reload_nested_set
elsif position != :root
# load object if node is not an object
target = nested_set_scope.find(target)
end
self.reload_nested_set
The line:
target = nested_set_scope.find(target)
The find() method will raise an ActiveRecord::RecordNotFound Exception
but if replace find() with find_by_id() method will get another error:
NoMethodError: undefined method `left' for nil:NilClass
How to resolve this issue ?
it is executed before class before_destory callbacks witch makes problem -
before filter checks if there is any articles in descendants
def check_if_category_or_descendants_have_any_articles
KnowledgeBase::Article.in_category(self).count == 0
end
but before it is executed all descendants are delete from db and i don't know how to solve this
Second issue is connect with updating of lft and rgt even when deleting leaf
KnowledgeBase::Category Delete all (0.3ms) DELETE FROM "knowledge_base_categories" WHERE ("lft" > 2 AND "rgt" < 3) KnowledgeBase::Category Update (0.3ms) UPDATE "knowledge_base_categories" SET "lft" = ("lft" - 2) WHERE ("lft" > 3) KnowledgeBase::Category Update (0.4ms) UPDATE "knowledge_base_categories" SET "rgt" = ("rgt" - 2) WHERE ("rgt" > 3) SQL (1.0ms) SELECT count(*) AS count_all FROM "knowledge_base_articles" WHERE (category_id IN (SELECT id FROM knowledge_base_categories WHERE lft >= 2 AND rgt <= 3))
sollution for leaf problem is straight forward
# back to the left so the counts still work.
def destroy_descendants
return if leaf? || right.nil? || left.nil? || skip_before_destroy
but i don't know how to solve problem with triggering callback (destroy_descendants)
meybe it should be executed after node is destroyed
category.level issues a query every time. Isn't it a better option we cache level for each record by adding a field level in a model and calculate at create or move actions only. Or we can calculate level for any category by just adding 1 to the level of its parent object.
I'm having problems where when I move A to be the child of B, A doesn't show up in B.descendants, even though B shows up in A.ancestors.
Is there a reason this shouldn't pass?
def test_assigning_parent_on_create
category = Category.create!(:name => "Child", :parent => categories(:child_2))
assert_equal categories(:child_2), category.parent
assert_equal categories(:child_2).id, category.parent_id
assert_not_nil category.left
assert_not_nil category.right
assert Category.valid?
assert categories(:child_2).descendants.include? category
end
(taken from awesome_nested_set_test.rb)
Use of self.class.table_name in awesome_nested_set.rb lines:
292, 313, 325, 364, 365, 370, 420 (only tested with line 292, but I assume it's the same in all instances)
Throws MySQL syntax error 1064 when SQL reserved words are used as table names.
I believe it should be replaced with quoted_table_name to add backticks to SQL table names.
Hi,
as far as i see, its not possible to move a node into a different tree (scope). Is it? Why not?
For example I have a node with :scope=>nil, :parent=>nil, :lft=>1, :rgt=>2
And another node with :scope=>1,:paranet=>nil, :lft=>1, :rgt=>2
And wanted to move the first one to child of second one.
Thanks and regards, Phil
Hey dude,
We've been using your plugin recently and while it is super cool and has sped things up considerably, we encountered a couple of nasty bugs on the creation of our hierarchical objects.
Specifically, lines 516 and 570 of awesome_nested_set.rb in #move_to cause an ActiveRecord reload which in turn halts the after_save filter chain.
We haven't been able to come up with a proper solution, so the workarounds we've implemented involve a) always invoking acts_as_nested_set after any other chains and b) always saving the newly created object before assigning any has_many association objects (this seems to be because usage of the << operator on has_many associations of unsaved new objects causes an after_save to be set up to subsequently create the join table entries).
Not sure what you can do, but thought I should bring it to your attention.
Regards,
Elliot Crosby-McCullough
Eden Development
I just updated the plugin http://github.com/mbleigh/acts-as-taggable-on
from 1.1.9 to 2.0.4 and since then awesome_nested_set is broken for me, i cannot create new elements.
On save i get the following errors:
http://pastebin.com/bAmXeMAU
I posted an isee at tagg-plugin as well.
See http://github.com/mbleigh/acts-as-taggable-on/issues/issue/55
using rails 2.3.5 and both as plugins
Hi,
I understand the logic and mechanics behind nested set, but I have a question regarding concurrency. We've got multiple independent processes creating nodes in the nested set.
I understand during the insertion of new nodes, that the tree to the right of the new node needs to move to the right by having each nodes lft and rgt increased by +2.
Is there any table locking going on in awesome_nested_set, that would safeguard one process' move_to operation from trampling over another's ? I don't see anything in the code that would suggest that.
Kind regards,
Ijonas.
I've set up a basic Category model, with a schema table that looks like this:
create_table "categories", :force => true do |t|
t.integer "parent_id"
t.string "name"
t.text "description"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "lft"
t.integer "rgt"
end
In my Category model, I have the following line:
attr_accessible :name, :description, :parent_id
I've implemented a form partial to edit or add a new category, using the example code in the readme to create a select:
<%= f.select :parent_id, nested_set_options(Category, @category) {|i| "#{'-' * i.level} #{i.name}" } %>
When I submit the new category form, the following error occurs:
RuntimeError in CategoriesController#create
Declare either attr_protected or attr_accessible for Category, but not both.
Any help would be appreciated.
The error occurred while evaluating nil.-
/Users/SCRUBBED/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb:260:in `leaf?'
I am trying to run tests for this plugin by "rake test:plugins --trace" from the root of the application. The result I am getting is the following. Any idea to solve this would be greatly appreciated.
C:\Ruby\bin\ruby.exe -e STDOUT.sync=true;STDERR.sync=true;load($0=ARGV.shift) C:\Ruby\bin/rake test:plugins --trace
Testing started at 10:48 ...
(in C:/Users/andreas/RubymineProjects/multiple_nested_set)
** Invoke test:plugins (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute test:plugins
C:/Ruby/bin/ruby.exe -I"lib;test" "C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "vendor/plugins/awesome_nested_set/test/awesome_nested_set/helper_test.rb" "vendor/plugins/awesome_nested_set/test/awesome_nested_set_test.rb"
C:/Ruby/lib/ruby/gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:440:in load_missing_constant': uninitialized constant CollectiveIdea::Acts::NestedSet::TestCaseClass (NameError) from C:/Ruby/lib/ruby/gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:80:in
const_missing'
from ./vendor/plugins/awesome_nested_set/test/awesome_nested_set/helper_test.rb:6
from C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb:5:in load' from C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb:5 from C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb:5:in
each'
from C:/Ruby/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb:5
rake aborted!
Given a model as such:
class Category < ActiveRecord::Base
validates_presence_of :name
validates_uniqueness_of :name, :scope => :parent_id
acts_as_nested_set
end
And this should then pass:
@root = Factory(:category, :name => "one")
@sub = Factory(:category, :name => "two")
@sub.move_to_child_of(@root)
@sub.update_attribute(:name, "one")
@sub.move_to_root
assert_equal @root.id, @sub.parent_id
I'm assuming that @sub.move_to_root
wouldn't succeed since it would update the record into an invalid state. If that sounds unreasonable, please let me know.
Current the order for the children assocation is hard-coded to the left column, being able to change this would be very useful. I am not sure if we would need to replace the default ordering or add to so that we could have something like
has_many :children, :class_name => self.base_class.to_s, :foreign_key => parent_column_name, :order => "#{quoted_left_column_name}, #{an_override}"
My Organization model acts_as_nested_set:
org1 = Organization.find(1)
org2 = Organization.find(2)
org2.move_to_child_of(org1)
This gives the following error:
NoMethodError: undefined method callback' for #<Organization:0x10323af10> from […]/activemodel/lib/active_model/attribute_methods.rb:240:in
method_missing'
from […]/activerecord/lib/active_record/attribute_methods.rb:38:in method_missing' from […]/plugins/awesome_nested_set/lib/awesome_nested_set.rb:507:in
move_to'
from […]/plugins/awesome_nested_set/lib/awesome_nested_set.rb:404:in `move_to_child_of'
I wish I knew more about how to fix this, but it seems that Rails 3.0 changed the way it handles callbacks? I am using Edge Rails which I set up with these instructions. Am I missing something, or does anyone have any ideas?
Can I trouble you to provide a little more detail in Step 3 on http://wiki.github.com/collectiveidea/awesome_nested_set/converting-acts_as_tree-to-awesome_nested_set
Many thanks!
There is a descendants
method, however this fetches all descendants into a flat collection. Often times one wants a nested collection of descendants where they can iterate through children and sub-children at each level.
It would be great if there was a method called nested_children
or something which would call descendants but then remap the nesting in memory. So calling nested_children
on a child would not trigger an SQL call but return the sub-children mapped in memory. One could use recursion to display this. For example:
<ul> <% for child_node in node.nested_children %> <li><%= render child_node %></li> <% end %> </ul>
I believe this would also help improve performance on the select helper method since isn't this currently performing a separate SQL query each time the children are fetched?
As per this post we're by default setting attr_accessible
to nil
on all our models by using the following in an initializer:
ActiveRecord::Base.send(:attr_accessible, nil)
and then explicitly specifying which fields should be open to mass-assignment in the individual models.
awesome_nested_set
uses attr_protected
to protect the left/right columns which I assume to be the source of the RuntimeError: Declare either attr_protected or attr_accessible for Comment, but not both.
error that we're geting in our functional tests.
This little hack to /lib/awesome_nested_set.rb
seems to resolve this issue:
# no bulk assignment
[left_column_name.intern, right_column_name.intern].each do |protected_attr|
attr_protected protected_attr if self.attr_accessible.include?(protected_attr)
end
AwesomeModel.all(:order => foo) works but AwesomeModel.roots(:order => foo) doesn't.
??
I have just installed awesome_nested_set, and I am getting the following error when I try to use the move_to_child_of method on an object whose model is configured with acts_as_nested_set:
NoMethodError (undefined method `move_to_child_of')
What could be causing this? I am using Rails 2.3.8 and ruby 1.8.7 (2010-06-23 patchlevel 299) [i386-mingw32].
I installed the plugin, ran the migration and added it to a model. Runnning 'rake' raised the following warnings:
DEPRECATION WARNING: Base.named_scope has been deprecated, please use Base.scope instead. (called from acts_as_nested_set at /rails/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb:89)
DEPRECATION WARNING: Base.named_scope has been deprecated, please use Base.scope instead. (called from acts_as_nested_set at /rails/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb:90)
I'm posting this solution in case anyone else encounters this problem when using this great plugin.
I test using FactoryGirl and Shoulda. When I first started writing my tests, I was getting NoMethodErrors on some of the test methods provided by AwesomeNestedSet. As part of the philosophy of FactoryGirl, I was avoiding setting the lft
and rgt
values in my Factories as that lead to highly defined code that could easily become brittle in robust testing.
The answer to the problem lies in the very helpful rebuild! method. After creating models in the Factory, rebuild! the nested set and all of the methods magically become available. This dynamically created the boundary values appropriate to whatever you have designed in your testing code.
# Media Types Factories Factory.define :media_type do |f| f.name 'media type' end Factory.define :media_type_child, :class => MediaType do |f| f.name 'child media type' end
# Testing code Excerpt context "when there is a parent" do setup do @parent = Factory.create(:media_type) MediaType.rebuild! post :create, :media_type => Factory.attributes_for(:media_type_child), :parent => @parent.id end # Working Test should "be a child type" do assert assigns(:media_type).child? end # Working Test should "be a child of the parent" do assert assigns(:media_type).is_descendent_of?(assigns(:parent)) end end
Hello!
When you set parent_id = 0 it raises NoRecord error with ID = 0.
imho it would be more logical to define this method like this:
def move_to_new_parent
if @move_to_new_parent_id.nil? || @move_to_new_parent_id == 0
move_to_root
elsif @move_to_new_parent_id
move_to_child_of(@move_to_new_parent_id)
end
end
It allows to create select field with mandatory selection:
<select name="parent_id"> <option value="">--select parent--</option> <option value="0">none</option> <option value="1">parent1</option> <option value="2">parent2</option> </select>
Hi, I hope this is the good place to ask this,
I have two tables in my db, one with MAIN categories, and another for the categories that each of my customers grab for it's businness.
id
name
parent_id
lft
rgt
id
name
parent_id
rgt
lft
customer_id
Ok, that said, I have a view with the typical two multiselect list's, one next to the other, with two buttons between them to "switch" categories, so the customer can grab any categories he wants from the main list.
I already wrote the code to grab categories and save them in 'customer_categories', after that I refresh my two select lists via ajax, so I get my Customercategories.all(:conditions => ['box_id = ?'], params[:customer_id]) to refresh the second list, but the problem comes when I have to refresh my first list, which would be this (in a veeeeeery simplificated way):
@first_list = Categories.all - Customercategories.all(:conditions => ['box_id = ?'])
I am hanging around this trying to write an algorithm to do it but it doesn't seem very easy, since I have to take in consideration ancestors/descendents etc...
Maybe you can show me the path to go ?
Thanks a lot,
cocozz
I have has_one assiociation with nested_attributes enabled. Before including awesome_nested_set everything works just fine. After adding awesome_nested_set the nested attributes for the has_one assiociation are lost. I "fixed" it in my code to use an has_many.
I have no clue why or how this is happening.
Not so much an issue as a feature request. (Sorry if misfiled. Couldn't see a Lighthouse link or similar.)
It would be great if we had the option of setting parent_id directly sometimes, rather than always using move_to_child_of.
For example, I use seed_fu (http://github.com/mbleigh/seed-fu/tree/master) to seed my development database, and seed_fu can only assign values to instance variables -- it can't call methods from plugins. I'd like to be able to do something like this in seed_fu:
Thing.seed do |s|
s.id = "2"
s.parent_id = "1"
end
Hi there, just thought perhaps there should be consideration in the rebuild! method for a position column. This is nice for people converting from acts as tree with acts as list for positioning. I just hacked the method to sort by position rather than left, right and id. Worked a charm, but perhaps there could be some kind of parameter passed in to override the ordering?
Also found this plugin for those struggling with drag and drop sorting after converting to nested set. I didn't end up using it because it's designed for dragging and dropping between different parents, but I took the basics and applied it to my project. It works well :)
http://github.com/robinsp/sortable_element_for_nested_set/tree/master
Currently, a helper exists to generate a dropdown of categories. However, explicitly assigning parent_id raises an ActiveRecord::ActiveRecordError, so you'd have to do something like:
class Admin::CategoriesController < Admin::BaseController
before_filter :remove_parent_id, :only => [:create, :update]
resource_controller
create.after { @category.move_to_child_of(@parent_id) unless @parent_id.blank? }
update.after { @category.move_to_child_of(@parent_id) unless @parent_id.blank? }
private
def remove_parent_id
@parent_id = params[:category].delete(:parent_id)
end
end
I think that either assigning to parent_id should be allowed or the helper get removed so as to not confuse developers.
When working with a massive nested set and relocating a node, it is possible that this will cause a cascade of left/right recalculations affecting tons of other records. Moving a single node should have a minimal impact on other nodes. From my limited observation this results because the left/right assignments across the nesting are sequential and without a gap. By providing an offset, this allows us to avoid a cascading recalculation of nesting in many cases. (This is similar to old-time programming where programmers hand-entered line numbers in increments of 10 in case new lines had to be added in the future.) In this way, only when gaps are filled and a collision occurs, would an across-the-board recalculation be necessary.
Hello,
I'm using successfully this plug-in.
But I move a node, sometime I'd like it to be the FIRST children of it's new parent, not the last as it appears to be the case for now...
I was considering doing of dirty hack, but I don't really understand the code of move_to, and I'd like not to break my existing code.
So if you see a simple way of doing that, please tell me !
Regards,
I've run into some bother when trying to 'seed' my CMS with a root folder and a page within that folder. Basically the seeding happens when the application finds its database empty, so only on a new instance of the CMS. What is happening is The folder gets created with left and right of 1, 2, then even though the page is created with the parent being the folder, the left and right of the page is 3, 4.
I've tested just seeding the database with a folder, then making a page within it using the application (like a normal user would) and it all works well. The process I'm using to seed the page is the same as a user would, just that it happens in the same process call, rather than being executed in a separate request to the server.
I'm presuming there's some kind of refresh that needs to take place so that awesome_nested_set will place the page within the folder properly?
I'm curious what a proper index would be for lft and rgt. For parent_id it's pretty obvious. This website (http://threebit.net/tutorials/nestedset/tutorial1.html) seems to indicate that they should be unique indexes. Do you agree?
Column | Type | Notes
---------+--------+-----------
nid | bigint | Primary Key
parentId | bigint | Foreign Key (nestedSet.nid)
rft | bigint | Unique Key
lft | bigint | Unique Key
I get this error when running doc:plugins:awesome_nested_set, I installed rdoc_html_templates but doesn't do anything:
My gems:
rails (2.3.5)
rake (0.8.7)
rdoc (2.4.3)
rdoc_html_templates (2.3.0)
Thanks for your help !
cocozz@kakawette ~/dev/enruscats/trunk/ $ rake doc:plugins --trace
(in /home/cocozz/dev/enruscats/trunk)
** Invoke doc:plugins (first_time)
** Invoke doc:plugins:awesome_nested_set (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute doc:plugins:awesome_nested_set
rdoc -o doc/plugins/awesome_nested_set --title 'Awesome Nested Set Plugin Documentation' --line-numbers --inline-source --charset utf-8 -T html vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb vendor/plugins/awesome_nested_set/lib/awesome_nested_set/helper.rb
--inline-source will be removed from RDoc on or after August 2009
Parsing sources with 2 thread(s)...
100% [ 2/ 2] vendor/plugins/awesome_nested_set/lib/awesome_nested_set/helper.rb
Generating Darkfish...
uh-oh! RDoc had a problem:
could not find template "html"
run with --debug for full backtrace
rake aborted!
Command failed with status (1): [rdoc -o doc/plugins/awesome_nested_set --t...]
/home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:995:in sh' /home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:1010:in
call'
/home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:1010:in sh' /home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:1094:in
sh'
/home/cocozz/dev/enruscats/trunk/vendor/rails/railties/lib/tasks/documentation.rake:84
/home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:636:in call' /home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:636:in
execute'
/home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:631:in each' /home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:631:in
execute'
/home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:597:in invoke_with_call_chain' /usr/lib/ruby/1.8/monitor.rb:242:in
synchronize'
/home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:590:in invoke_with_call_chain' /home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:607:in
invoke_prerequisites'
/home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:604:in each' /home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:604:in
invoke_prerequisites'
/home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:596:in invoke_with_call_chain' /usr/lib/ruby/1.8/monitor.rb:242:in
synchronize'
/home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:590:in invoke_with_call_chain' /home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:583:in
invoke'
/home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:2051:in invoke_task' /home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:2029:in
top_level'
/home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:2029:in each' /home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:2029:in
top_level'
/home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:2068:in standard_exception_handling' /home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:2023:in
top_level'
/home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:2001:in run' /home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:2068:in
standard_exception_handling'
/home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/lib/rake.rb:1998:in run' /home/cocozz/.gem/ruby/1.8/gems/rake-0.8.7/bin/rake:31 /usr/bin/rake:19:in
load'
/usr/bin/rake:19
Hello.
I have installed plugin into my rails 3 app.
I can create root nodes but when I am trying to create a sub-node(move_to_child_of or create method's params include parent) i am getting an error below:
NoMethodError: undefined method proxy_options' for #<ActiveRecord::NamedScope::Scope:0x7f083cf81510> from /var/lib/gems/1.8/gems/activerecord-3.0.0.beta/lib/active_record/relation.rb:318:in
method_missing'
from /var/lib/gems/1.8/gems/activerecord-3.0.0.beta/lib/active_record/named_scope.rb:183:in method_missing' from /var/rails/market/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb:567:in
move_to'
from /var/lib/gems/1.8/gems/activerecord-3.0.0.beta/lib/active_record/connection_adapters/abstract/database_statements.rb:136:in transaction' from /var/lib/gems/1.8/gems/activerecord-3.0.0.beta/lib/active_record/transactions.rb:182:in
transaction'
from /var/lib/gems/1.8/gems/activerecord-3.0.0.beta/lib/active_record/transactions.rb:188:in transaction' from /var/rails/market/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb:509:in
move_to'
from /var/rails/market/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb:405:in `move_to_child_of'
from (irb):1
Hi there, just wondering if you could explain why the children method isn't a traditional has_many relationship? I had an issue where I wanted to find a polymorphicly related set of records through the children of a parent run by awesome_nested_set but had to mock up another model to do this because :children isn't a reflection.
See this post: http://stackoverflow.com/questions/1080942/recreating-this-custom-query-using-hasmany/1082977#1082977
I'm sure there's probably a very good reason, I'm just interested to find out :)
acts_as_tree enable to config counter_cache and I need this feature.
Why not adding :counter_cache to the options and belongs_to :parent config ?
Hello,
I'm using AwesomeNestedSet to replace acts_as_list and acts_as_tree and i'm very satisfied.
And now, i'm trying to make a interface to reorder tree using sortable_element provided by Rails but I dont know how I can reorder records using the received params by Script.aculo.us.
I tryed this plugin http://github.com/robinsp/sortable_element_for_nested_set without success also.
I don't know if this is a feature request or a possible "plugin" of AwesomeNestedSet. You can talk about this feature?
Best regards
def move_to wraps its db update in a transacion, which is quite ok. But when creating a new record for an object which also saves with a transaction(with optimistic locking via col =>lock_version) AR chockes when reloading the current object in line 570 because the record is not saved yet.
I guess reloading is done so other callbacks can see the update, i just commented out the line which works for me.
(.. AR callbacks, locking and transactions shot me in the foot a couple of times)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.