Git Product home page Git Product logo

closure_tree's People

Contributors

aaroalan avatar aaronrussell avatar alagram avatar elhoyos avatar elskwid avatar envek avatar eturino avatar fabien-michel avatar fd avatar garygreyling avatar hendricius avatar iamtheschmitzer avatar jturkel avatar juddblair avatar kazalt avatar kimufly avatar kirs avatar mceachen avatar mikeastock avatar mkralla11 avatar n-rodriguez avatar nbekirovacronis avatar pgericson avatar r4do avatar richkuo avatar robotdana avatar seuros avatar sturgill avatar swrobel avatar weilandia avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

closure_tree's Issues

Create Navigation for CMS Content

Hey there,
i'm currently working on a cms where i use closure tree for managing the web pages.
Now i want to do a navigation so i wanted to use Page.hash_tree.

@Navigation = Page.hash_tree(:limit_depth => 2) creates this error "undefined method []=' for nil:NilClass" in closure_tree (3.6.4) lib/closure_tree/acts_as_tree.rb:113:inblock in hash_tree'
can someone help me? would be great ;)

kind regards,
patrick

Possible missing results

Hi, I was working with Closure-tree gem and I noticed this

1.9.3p194 :019 > m.self_and_ancestors
=> [# CuisineType id: 27, name: "m", parent_id: 22 ]

so we have "m" with a parent... not in the list

1.9.3p194 :020 > m.parent
=> # CuisineType id: 22, name: "e", parent_id: nil

For me, the "logic" behaviour should be smth like
console > m.self_and_ancestors
=> [# ...m..., #...e...]

At least I've resolved it creating my own function (recursive simple one). I've posted it just for "help the developers if it were really a bug"

Apart from that the gem is sooo nice ^^

Manu

Prepending when using Deterministic ordering with Polymorphic hierarchies updates position of only the same type

Hello, I'm having a problem using Deterministic ordering with Polymorphic hierarchies with STI.
In my project I'm moving elements of different types. When I move an element in between it's siblings the resulting SQL statement updates the sort_order column of only elements of the same type.

For example:

  • Element A is type "Text" with "sort_order" 1
  • Element B is type "Group" with "sort_order" 2
  • Element C is type "Photo" with "sort_order" 3
  • All of these elements have the same parent.

If I prepend Element A to C then the resulting SQL statement is:
UPDATE elements SET sort_order = sort_order - 1 WHERE elements.type IN ('Photo') AND (parent_id = ## AND sort_order <= 2))

So, only elements type "Photo" have their "sort_order" value updated resulting in:
Element C remains with a "sort_order" value of 3 while element A and B now have a "sort_order" value of 2.

How can I override this behavior and have that moving an element updates the order of all siblings before or after it?

Render as nested JSON

Hello. Is there any way to render nested resources as JSON? I use closure_tree to implement comments with replies and the method "hash_tree" is very helpful when rendering all this heirarchy in plain HTML. But how can I render the same stuff in JSON, for example like (or anything like this - i just basically need some mechanism to mark which comments are roots, which are children and to which roots they related, in order to render it with AngularJS):

[
  {
    body: "Text of the comment"
    name: "Username"
    comment:
    {
       body: "Nested comment"
       name: "User who posted nested comment",
       comment:
       {
         body: "2 levels nested comment"
         name: "Username"
         comment:
         {
            ....
         }
       }
    }
  }
]

Any help will be much appreciated.

Optimize Tree.hash_tree

Right now it just executes the :hash_tree method for each root. So it's potentially a O(N) query. It can be done in one swipe, preloading by generation including the roots:

scope = Category.select("categories.*, category_hierarchies.*").
     joins("left join category_hierarchies on ancestor_id = categories.id").
     order("parent_id IS NOT NULL, generations ASC, name")

Rails 3.2: NoMethodError in `acts_as_tree_before_save'

Here's part of my exception_notification email:

A NoMethodError occurred in product_groups#update:

  undefined method `ActiveRecordError' for ActiveRecord:Module
  closure_tree (3.0.0) lib/closure_tree/acts_as_tree.rb:172:in `acts_as_tree_before_save'

Rails (and ActiveRecord) is 3.2.1, closure_tree 3.0.0

Preorder traversal sequence on descendants

I believe this can be a very particular feature, but do you have any thoughts on making tag.descendants return its results with a preorder sequence? What would you recommend?

grandparent = Tag.find_or_create_by_path(["grandparent", "parentA", "childA"]).parent.parent
Tag.find_or_create_by_path(["grandparent", "parentB", "childB"])
grandparent.descendants
=> ["parentA", "parentB", "childA", "childB"] # current traversal sequence
=> ["parentA", "childA", "parentB", "childB"] # preorder traversal sequence 

STI and children.create

When calling create on the children's type is not passed to the newly created child.

Piggybacking on the example provided

class Tag < ActiveRecord::Base
  acts_as_tree
end
class WhenTag < Tag ; end
class WhereTag < Tag ; end
class WhatTag < Tag ; end
now = WhenTag.create name: 'Now'
now.children
=> []
right_now = now.children.create name: 'Right now'
right_now.type
=> nil

I was expecting the type to be kept. I don't know if I'm asking too much from closure_tree and this is just not supposed to be kept. Meanwhile I'll set it up manually or create the child using WhenTag.create and assign it to its parent later.

Thank you!

Hey, I'm just opening this to thank you publicly and to tell you how much I appreciate the work you've been doing on this project. Keep it rolling, you rock!

p.s please close this once you read it :)

Observers on numerically sorted hierarchical models trigger load error

Hello @mceachen,

Just uncovered an interesting issue today and wanted to discuss how it should be handled. I was seeing errors from active record where my hierarchical model table didn't exist during a rake run.

Turns out that there was an observer on that same model (the one that has acts_as_tree order: "name" defined). That observer loads the model and the order option then attempts to look up column information on the table.

This isn't a problem unless you're in an environment like Travis CI (or any environment that starts without a database defined).

No database to start

  • Execute rake db:setup
  • Rake starts
  • Environment loads
  • Observers are loaded
  • Observers load the observed models
  • acts_as_tree order: "field_name" needs to include ClosureTree::DeterministicNumericOrdering if order_is_numeric
  • order_is_numeric calls ct_class.columns_hash[order_option]
  • columns_hash access the ActiveRecord metadata for the table
  • The table doesn't exist so the rake task fails

Observers are scheduled for removal in Rails 4 but I've seen you mention the desire to maintain support for older Rails versions for this project.

I am happy to help fix this issue, just not sure how or if you'd like it fixed. My initial reaction was to change order_is_numeric as follows (although I hate && in unless):

def order_is_numeric
  return false unless order_option && self.table_exists?
  c = ct_class.columns_hash[order_option]
  c && c.type == :integer
end

If you'd like a pull request I can put one together and get this moving.

Thanks for a great project!

Testing setup

I was wondering if you could provide some steps for how to set up a testing environment for this gem? I had a quick go but came unstuck pretty fast. It looks like you use rbenv for your larger test suite but is there a way to get a basic test setup going on say one database, ruby and rails version?

Creating trees from unsaved records leading to duplicate key value constraint issues

Hey there. Lovely library you have here.

I have a class like:

class Field
  acts_as_tree order: 'sort_order', dependent: :destroy, name_column: :body
end

I am trying to build a tree and then save all at once, e.g.

a = Field.new(body: "a")
b = Field.new(body: "b")
c = Field.new(body: "c")
a.children << b
b.children << c
a.save

I then get this error:

1.9.3p194 :009 > a.save
   (0.1ms)  BEGIN
  SQL (8.2ms)  INSERT INTO "fields" ("body", "created_at", "extra", "form_id", "parent_id", "required", "sort_order", "type", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING "id"  [["body", "a"], ["created_at", Thu, 26 Jul 2012 14:11:05 EDT -04:00], ["extra", nil], ["form_id", 31], ["parent_id", nil], ["required", false], ["sort_order", nil], ["type", "Field::MultipleChoice"], ["updated_at", Thu, 26 Jul 2012 14:11:05 EDT -04:00]]
  Field Load (0.8ms)  SELECT "fields".* FROM "fields" WHERE "fields"."id" = 255 ORDER BY sort_order ASC LIMIT 1
  FieldHierarchy Load (0.5ms)  SELECT "field_hierarchies".* FROM "field_hierarchies" WHERE "field_hierarchies"."descendant_id" = 255 ORDER BY "field_hierarchies".generations asc
  SQL (0.6ms)  INSERT INTO "fields" ("body", "created_at", "extra", "form_id", "parent_id", "required", "sort_order", "type", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING "id"  [["body", "b"], ["created_at", Thu, 26 Jul 2012 14:11:05 EDT -04:00], ["extra", nil], ["form_id", 31], ["parent_id", 255], ["required", false], ["sort_order", nil], ["type", "Field::MultipleChoice"], ["updated_at", Thu, 26 Jul 2012 14:11:05 EDT -04:00]]
  Field Load (0.4ms)  SELECT "fields".* FROM "fields" WHERE "fields"."id" = 256 ORDER BY sort_order ASC LIMIT 1
  FieldHierarchy Load (0.3ms)  SELECT "field_hierarchies".* FROM "field_hierarchies" WHERE "field_hierarchies"."descendant_id" = 256 ORDER BY "field_hierarchies".generations asc
  SQL (1.2ms)  INSERT INTO "fields" ("body", "created_at", "extra", "form_id", "parent_id", "required", "sort_order", "type", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING "id"  [["body", "c"], ["created_at", Thu, 26 Jul 2012 14:11:05 EDT -04:00], ["extra", nil], ["form_id", 31], ["parent_id", 256], ["required", false], ["sort_order", nil], ["type", "Field::MultipleChoice"], ["updated_at", Thu, 26 Jul 2012 14:11:05 EDT -04:00]]
  SQL (0.4ms)  INSERT INTO "field_hierarchies" ("ancestor_id", "descendant_id", "generations") VALUES ($1, $2, $3)  [["ancestor_id", 257], ["descendant_id", 257], ["generations", 0]]
   (0.4ms)   INSERT INTO "field_hierarchies"
 (ancestor_id, descendant_id, generations)
 SELECT x.ancestor_id, 257, x.generations + 1
 FROM "field_hierarchies" x
 WHERE x.descendant_id = 256

  Field Load (0.3ms)  SELECT "fields".* FROM "fields" WHERE "fields"."parent_id" = 257 ORDER BY sort_order ASC, sort_order
  SQL (0.1ms)  INSERT INTO "field_hierarchies" ("ancestor_id", "descendant_id", "generations") VALUES ($1, $2, $3)  [["ancestor_id", 256], ["descendant_id", 256], ["generations", 0]]
   (0.2ms)   INSERT INTO "field_hierarchies"
 (ancestor_id, descendant_id, generations)
 SELECT x.ancestor_id, 256, x.generations + 1
 FROM "field_hierarchies" x
 WHERE x.descendant_id = 255

  SQL (0.5ms)  INSERT INTO "field_hierarchies" ("ancestor_id", "descendant_id", "generations") VALUES ($1, $2, $3)  [["ancestor_id", 257], ["descendant_id", 257], ["generations", 0]]
   (0.2ms)  ROLLBACK
ActiveRecord::RecordNotUnique: PG::Error: ERROR:  duplicate key value violates unique constraint "index_field_hierarchies_on_ancestor_id_and_descendant_id"
DETAIL:  Key (ancestor_id, descendant_id)=(257, 257) already exists.
: INSERT INTO "field_hierarchies" ("ancestor_id", "descendant_id", "generations") VALUES ($1, $2, $3)
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/connection_adapters/postgresql_adapter.rb:1171:in `get_last_result'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/connection_adapters/postgresql_adapter.rb:1171:in `exec_cache'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/connection_adapters/postgresql_adapter.rb:665:in `block in exec_query'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/connection_adapters/abstract_adapter.rb:280:in `block in log'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activesupport-3.2.7.rc1/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/connection_adapters/abstract_adapter.rb:275:in `log'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/connection_adapters/postgresql_adapter.rb:663:in `exec_query'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/connection_adapters/abstract/database_statements.rb:63:in `exec_insert'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/connection_adapters/abstract/database_statements.rb:90:in `insert'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/connection_adapters/abstract/query_cache.rb:14:in `insert'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/relation.rb:66:in `insert'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/persistence.rb:367:in `create'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/timestamp.rb:57:in `create'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/callbacks.rb:268:in `block in create'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activesupport-3.2.7.rc1/lib/active_support/callbacks.rb:403:in `_run__1815317462497579710__create__1621482155338212246__callbacks'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activesupport-3.2.7.rc1/lib/active_support/callbacks.rb:405:in `__run_callback'
... 62 levels...
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/validations.rb:50:in `save'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/attribute_methods/dirty.rb:22:in `save'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/transactions.rb:241:in `block (2 levels) in save'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/transactions.rb:295:in `block in with_transaction_returning_status'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/connection_adapters/abstract/database_statements.rb:192:in `transaction'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/transactions.rb:208:in `transaction'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/transactions.rb:293:in `with_transaction_returning_status'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/transactions.rb:241:in `block in save'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/transactions.rb:252:in `rollback_active_record_state!'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/activerecord-3.2.7.rc1/lib/active_record/transactions.rb:240:in `save'
    from (irb):9
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/railties-3.2.7.rc1/lib/rails/commands/console.rb:47:in `start'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/railties-3.2.7.rc1/lib/rails/commands/console.rb:8:in `start'
    from /Users/chrismcc/.rvm/gems/ruby-1.9.3-p194-fast@amanda/gems/railties-3.2.7.rc1/lib/rails/commands.rb:41:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'1.9.3p194 :010 >

Any ideas?

Note that it DOES work if I do:

a = Field.new(body: "a")
b = Field.new(body: "b")
c = Field.new(body: "c")
a.children << b
b.children << c
c.save
b.save
a.save

Thanks!

parent doesn't work when building associationg without saving to database

I have a really specific model validation that must ensure parent is not defined to enable some validations.

The problem is that if I create both the parent and the children without saving to the database (via build), it fails. Here is a code snippet:

class Category < ActiveRecord::Base
  acts_as_tree

  validates :code, :presence => {:if => first_level?}

  def first_level?
    parent.nil?
  end
end

here is how to make it fail:

c = Category.new(:code => '123')
c1 = c.children.build
c1.valid?
=> false

I've searched for the problem and found this patch submmited to rails 2.3.6 (it's old but still there): https://rails.lighthouseapp.com/projects/8994/tickets/2815-nested-models-build-should-directly-assign-the-parent

The solution is to use "inverse_of" while defining the associations. In theory it will fix this error.

Different options for STI models

Quick question: is it possible to have different acts_as_tree options for subclasses of a STI model? Specifically, can we do this:

def Person
  acts_as_tree
end

def Person::Teacher < Person
  acts_as_tree :order => 'age'
end

def Person::Student < Person
  acts_as_tree :order => 'name'
end

In this example, each teacher, ordered by age, has children ordered by name.

No method error when I try to use create or new

NoMethodError (undefined method `new' for #FileOrFolder:0x)

code :

newStructure = FileOrFolder.new
newStructure.fullpath = path
pathbits = path.split('/')
newStructure.name = pathbits.last

grandparent = newStructure.new(:name => "Grandparent")

has_many through self_and_descendants

I've got 2 models: User and Contract. User has many contracts but he should be able to see all of his and his descendants contracts. I tried something like this:

class User < ActiveRecord::Base
  acts_as_tree
  has_many :contracts, through: :self_and_descendants
end

class Contract < ActiveRecord::Base
  belongs_to :user
end

but i'm getting:

1.9.3p194 :058 > User.find(3).contracts
  User Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1  [["id", 3]]
SystemStackError: stack level too deep
    from gems/activerecord-3.2.6/lib/active_record/reflection.rb:530

is it possible to do such thing?

Adopt option for dependent?

What do you think about adding :adopt to the :dependent options... children of the deleted node are assigned to their grandparent node? If the deleted node is a "root" node it could then perform :nullify on the children instead?

[Rails 3.2.1] no file to load -- closure_tree/acts_as_tree

Strange, with v3.0.0 it works fine, with 3.0.1 and 3.0.2 not.. The Rails I'm using is 3.2.1, and here's what I get when trying to use 3.0.1 or 3.0.2:

$ rails server
/usr/lib/ruby/gems/1.8/gems/activesupport-3.2.1/lib/active_support/dependencies.rb:251:in `require': no such file to load -- closure_tree/acts_as_tree (LoadError)
    from /usr/lib/ruby/gems/1.8/gems/activesupport-3.2.1/lib/active_support/dependencies.rb:251:in `require'

(...)

I can't figure out, why is it happen..
I hope this time it's not my fault ;)

[QUESTION] Implementing version history with cloure_tree.

Hi, I already posted this question at http://stackoverflow.com/questions/13457479/implementing-version-history-with-a-closure-table-schema but I thought I should get mceachen's attention on it:

I have a custom CMS implementation that stores content nodes using the closure_tree gem.

The time has come for me to implement a version history where any change in the content tree (editing, inserting, moving, deleting nodes, etc.) would create a new version of the root node (a publication). And users would be able to look at older versions and revert back to them. The revert action would create a newer version which is a copy of the reverted one.

Is there a well known way to achieve this? or does anyone have an idea or example implementation for this sort of thing?

Thanks!

Error when sorting by column "name" and using includes(:self_and_descendants)

I have a category hierarchy and was trying to avoid N+1 queries by doing:

 Category.includes(:self_and_descendants).find(params[:id])

However, I am getting an error:

ActiveRecord::StatementInvalid: PG::Error: ERROR:  
    column "name" does not exist

Here is the SQL being generated

 Category Load (0.4ms)  SELECT "categories".*
    FROM "categories" 
    WHERE "categories"."id" = $1 LIMIT 1  [["id", 5]]
 CategoryHierarchy Load (0.6ms)  SELECT "category_hierarchies".* 
   FROM "category_hierarchies" 
   WHERE "category_hierarchies"."ancestor_id" IN (5) 
   ORDER BY "category_hierarchies".generations asc, name

My category model has an order by:

  acts_as_tree :order => 'name'

When I get rid of the ordering it works fine.

How can I use .includes(:self_and_descendants) and also order by name? Thanks

Escape `id` in SQL statements

Hi!

I'd like to use closure_tree on a project, but my objects use UUIDs as the primary key. Some SQL statements interpolate id directly, which fails for UUIDs because they need to be quoted. Maybe use ActiveRecord::Base.quote(id) instead?

self_and_ancestors - need for reload of model

Hi, it is quite counterintuitive, that 'self_and_ancestors' doesn't see changes to node until reload. Is it targeted behaviour and I should use reload in methods, which use these types of scopes?

x = Vega::Category.create(name: 'Parent2')
=> #<Vega::Category id: 3, name: "Parent2", position: 100, uri: "parent2", parent_id: nil, created_at: "2013-07-10 14:16:39", updated_at: "2013-07-10 14:16:39">

x.self_and_ancestors.to_a
=> []

x.reload
=> #<Vega::Category id: 3, name: "Parent2", position: 100, uri: "parent2", parent_id: nil, created_at: "2013-07-10 14:16:39", updated_at: "2013-07-10 14:16:39">

x.self_and_ancestors.to_a
=> [#<Vega::Category id: 3, name: "Parent2", position: 100, uri: "parent2", parent_id: nil, created_at: "2013-07-10 14:16:39", updated_at: "2013-07-10 14:16:39">]

Path and db views

I've had the need to have some sort of "path enumeration", and figured out a SQL query (that I use as a view) to do that:

      SELECT nodes.id AS node_id, nodes.name,
        ( SELECT group_concat(node.code separator '.') AS path
          FROM nodes as node
          JOIN node_hierarchies as tree
                ON (node.id = tree.ancestor_id)
           WHERE tree.descendant_id = nodes.id
          ) AS path
      from nodes;

The output of this query looks like:
1, "leaf node", 1.2.1.1
1, "leaf node 2", 1.2

This is useful to make for example, a search based on "path" (think auto complete).

I don't know exactly how it could be incorporated by the gem, but think it is useful enough to be considered for.

Order column (option) as a symbol

When setting the order column a string must be used, using a symbol won't work.

Works

acts_as_tree order: 'position'

It doesn't

acts_as_tree order: :position

I don't have a good explanation for why would this be better, other than it feels more natural and it wouldn't take much, changing:

https://github.com/mceachen/closure_tree/blob/master/lib/closure_tree/columns.rb#L71

# c = ct_class.columns_hash[order_option]
c = ct_class.columns_hash[order_option.to_s]

Should work with both strings and symbols.

UPDATE
I'm fairly new to testing, but a failing test could look something like this:

# spec/support/models.rb
class OtherLabel < Label
  acts_as_tree :order => :sort_order
end

# spec/label_spec.rb
  context "OtherLabel" do
    it "should include DeterministicNumericOrdering" do
      OtherLabel.include?(ClosureTree::DeterministicNumericOrdering).should be_true
    end
  end

Add or move nodes to a specific position

Here's how it currently works:

parent = Tag.create(:name => 'Parent')
child = parent.children.create(:name => 'Child')
# parent child: ['Child']

other_parent = Tag.create(:name => 'Other parent')
other_parent.children << child
# parent child: []
# other_parent child: ['Child']

You can add or move a node to a non-controlled position of another node. The order of the children' list of a node is determined by the id of the children.

On the other hand, it would be great if one could do this with the child list of other_parent:

second_child = other_parent.children.create(:name => 'Second child')
# ['Child', 'Second child']
third_child = Tag.create(:name => 'Third child')

third_child.move_to_right(child)
# ['Child', 'Third child', 'Second child']

third_child.move_to_left(child)
# ['Third child', 'Child', 'Second child']

We need to explicitly determine the order in which the children are set and retrieved: an order column index for every hierarchy.

This means:

  • maintain the order updated for every operation that affects the hierarchy.
  • adjust the methods that retrieve the tree elements to use this new order criteria.

Rails 4 or strong_parameters compatible

I get this message when I use this gem

attr_accessible is extracted out of Rails into a gem. Please use new recommended protection model for params(strong_parameters) or add protected_attributes to your Gemfile to use old one.

Maybe creating a branch or something like that for rails 4 closure_tree ?

.lock-closuretree-* files generated after each test run

I don't know if this is really an issue. I am using RSpec and every time I run a suite, a .lock-closuretree file is generated in my source's root directory. Is this expected or is there something wrong with my configuration?

Cannot preload self_and_descendants

When trying to load hash_tree as much effectively as can I came into an issue.
In model I have set order option act_as_tree order: 'name'
And then when trying to call Right.includes(:self_and_descendants) mysql throws error:

Unknown column 'name' in 'order clause

That's because ActiveRecord are trying to preload rIght_hierarchies without joining the model (Right) table.

I triet to dig into the code and find the bug. But only found that in closure_tree/model.rb there is _ct.has_many_with_order_option when defining has_many association on model.

Couldn't find out the way how to implement it to work with preloading and also preserve ordering feature on preloaded models.
Any ideas ?

move_to_child_of doesn't update the hierarchy table for descendants

I'm making the assumption that if I move a child to a new parent, all of the ancestor / descendent relationships would be updated within the hierarchy table - similar to when you simply add a child. Here is how I've addressed the issue:

module Ext
  module ClosureTree
    module ActsAsTree
      def move_self_and_descendants_to_child_of(parent)
        move_to_child_of parent
        children.each do |child|
          update_children_for_move self, child
        end       
      end

    private
      def update_children_for_move(parent, child)
        child.move_to_child_of parent
        child.children.each do |next_child|
          update_children_for_move child, next_child
        end       
      end
    end  
  end
end

ActiveRecord::Base.send(:include, Ext::ClosureTree::ActsAsTree)

2 types of children

Hey,

I'm building something weird.

I have one model, which is Post, and subclasses of it: Comment, Album, Photo.

class Post < ActiveRecord::Base
  acts_as_tree
end

Lets say I created an album, etc with these steps:

album = Album.create # <Album...
album.children # []

comment = Comment.create # <Comment...

# add the comment to be child of the album
album.children << comment

# create a photo
photo = Photo.create # <Photo...>

# add the comment to be child of the album
album.children << photo

# Let's create a photo doesnt belong to an album
Photo.create

Now here is my list action:

@posts = Post.roots.includes(:children).order('created_at DESC')

It will return Posts with eager loading all children (comments and photos). With the case above [Album, Photo] as parent and [Comment, Photo] as children of the Album.

The question: Is there any way to return for example: the children of the album [all the comment, and only 3 photos]?

Maybe in another words, how could parent have 2 trees of children?

rebuild! causes invalid INSERT rows using PostgreSQL

While running a migration file with Tag.rebuild! I encounter the following error:

PGError: ERROR: column "id" does not exist LINE 1: ...r_id", "descendant_id") VALUES(0, NULL, NULL) RETURNING "id"

This is because the join table lacks an id column and this is a problem for the PostgreSQL adapter, see this:

http://www.ruby-forum.com/topic/195472

Any idea how to get around this? Adding an id column is not possible because rails prohibits it for HABTM associations. Composite primary keys also do not work.

TIA,
Subhash

Doesn't work with table_prefixes

I'm using a table prefix, which is specified in application.rb like so:

config.active_record.table_name_prefix = "d2"

I have a model called "TagDefinition" that I have acts_as_tree on.

The problem is that acts_as_tree appears to look at the table name for TagDefinition, which due to the prefix is actually "d2_tag_definition", and then creates a model "D2TagDefinitionHierarchy" - ActiveRecord adds the table prefix to this, so it thinks the table name for this model is d2_d2_tag_definition_hierarchies. The actual table I added with the migration is d2_tag_definition_hierarchies.

So, the SQL queries in the gem where you manually insert the table name work fine, but if you do something like an ActiveRecord delete on TagDefinition (or pretty much anything where ActiveRecord tries to handle the generated Hierarchy object, rather than with manual SQL), it errors out when ActiveRecord uses the prefix and tries to select from d2_d2_tag_definition_hierarchies, which doesn't exist.

Rails had a similar bug in the table dumper, described here: rails/rails@1bdc098#activerecord/lib/active_record/schema_dumper.rb

I think if you change hierarchy_class_name to strip the prefix from the table name like rails did, you should be fine.

ActiveRecord::StatementInvalid (null value) on rebuild!

I've got problem when I'm trying to rebuild hierarchies table. Running User.rebuild! causes this error:
https://gist.github.com/1244628 (tried this on sqlite3 and postgresql)

My model:

class User < ActiveRecord::Base
  # invited_by_id comes from devise_invitable
  acts_as_tree parent_column_name: :invited_by_id
end

Migration file:

class CreateUsersHierarchies < ActiveRecord::Migration
  def change
    create_table :users_hierarchies, id: false do |t|
      t.integer  :ancestor_id, null: false   # ID of the parent/grandparent/great-grandparent/... tag
      t.integer  :descendant_id, null: false # ID of the target tag
      t.integer  :generations, null: false   # Number of generations between the ancestor and the descendant. Parent/child = 1, for example.
    end

    # For "all progeny of..." selects:
    add_index :users_hierarchies, [:ancestor_id, :descendant_id], unique: true

    # For "all ancestors of..." selects
    add_index :users_hierarchies, [:descendant_id]
  end
end

Is this a bug or am I doing something wrong?

Strong Parameters and Rails 3

After setting config.whitelist_attributes = false in application.rb, the model that is acting as a tree raises ActiveModel::MassAssignmentSecurity::Error. This is, because closure_tree is adding attr_accessible :parent (https://github.com/mceachen/closure_tree/blob/32da850126336fec6036ad8154a9b1fa738cb30e/lib/closure_tree/model.rb#L17)

https://github.com/mceachen/closure_tree/blob/32da850126336fec6036ad8154a9b1fa738cb30e/lib/closure_tree/support.rb#L23

    def use_attr_accessible?
      ActiveRecord::VERSION::MAJOR == 3 &&
        defined?(ActiveModel::MassAssignmentSecurity) &&
        model_class.ancestors.include?(ActiveModel::MassAssignmentSecurity)
    end

I beleive that this happens because of the last condition of use_attr_accessible?, which returns true even when using strong parameters. A better condition will be model_class.accessible_attributes.empty?, which returns true only when attr_accessible has been used in the model.

.hash_tree returning NoMethodError: undefined method `[]=' for nil:NilClass

I have a weird problem here. I added some nodes and suddenly I can't use Taxonomy.hash_tree anymore.

I thought, "ok, given I just started out, I'll just delete everything and start over", but then what if this issue happens when I go to production?

In fact, after starting over and recreating the nodes, I haven't got the error so far.

Do you have any idea what this could be?

Thanks!

Data

Here, everything's ok.

irb(main):003:0> Company.first.taxonomies.all
  Company Load (0.6ms)  SELECT "companies".* FROM "companies" LIMIT 1
  Taxonomy Load (0.3ms)  SELECT "taxonomies".* FROM "taxonomies" WHERE "taxonomies"."store_id" = 1
=> [#<Taxonomy id: 15, name: "a", parent_id: nil, store_id: 1, created_at: "2013-01-08 01:14:34", updated_at: "2013-01-08 01:14:34">, 
#<Taxonomy id: 16, name: "aa", parent_id: 15, store_id: 1, created_at: "2013-01-08 01:14:37", updated_at: "2013-01-08 01:14:37">, 
#<Taxonomy id: 17, name: "aaa", parent_id: 16, store_id: 1, created_at: "2013-01-08 01:14:40", updated_at: "2013-01-08 01:14:40">, 
#<Taxonomy id: 18, name: "b", parent_id: nil, store_id: 1, created_at: "2013-01-08 01:14:45", updated_at: "2013-01-08 01:14:45">, 
#<Taxonomy id: 19, name: "bb", parent_id: 18, store_id: 1, created_at: "2013-01-08 01:14:48", updated_at: "2013-01-08 01:14:48">, 
#<Taxonomy id: 20, name: "aaa2", parent_id: 16, store_id: 1, created_at: "2013-01-08 01:14:59", updated_at: "2013-01-08 01:14:59">, 
#<Taxonomy id: 21, name: "aaaa", parent_id: 20, store_id: 1, created_at: "2013-01-08 01:59:28", updated_at: "2013-01-08 01:59:28">, 
#<Taxonomy id: 22, name: "aaaa2", parent_id: 20, store_id: 1, created_at: "2013-01-08 01:59:34", updated_at: "2013-01-08 01:59:34">, 
#<Taxonomy id: 23, name: "aaa3", parent_id: 20, store_id: 1, created_at: "2013-01-08 01:59:38", updated_at: "2013-01-08 01:59:38">, 
#<Taxonomy id: 24, name: "a", parent_id: 9, store_id: 1, created_at: "2013-01-08 02:34:03", updated_at: "2013-01-08 02:34:03">, 
#<Taxonomy id: 25, name: "a", parent_id: 9, store_id: 1, created_at: "2013-01-08 02:34:08", updated_at: "2013-01-08 02:34:08">]

Problematic hash_tree

Here, the error.

irb(main):006:0> Company.first.taxonomies.hash_tree
  Company Load (0.7ms)  SELECT "companies".* FROM "companies" LIMIT 1
  Taxonomy Load (0.7ms)  SELECT "taxonomies".* FROM "taxonomies" INNER JOIN (
 SELECT descendant_id, MAX(generations) as depth
 FROM "taxonomy_hierarchies"
 GROUP BY descendant_id

 ) AS generation_depth
 ON "taxonomies".id = generation_depth.descendant_id WHERE "taxonomies"."store_id" = 1 ORDER BY generation_depth.depth
NoMethodError: undefined method `[]=' for nil:NilClass
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/bundler/gems/closure_tree-7bf33728b625/lib/closure_tree/acts_as_tree.rb:398:in `block in build_hash_tree'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/activerecord-3.2.9/lib/active_record/relation/delegation.rb:6:in `each'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/activerecord-3.2.9/lib/active_record/relation/delegation.rb:6:in `each'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/bundler/gems/closure_tree-7bf33728b625/lib/closure_tree/acts_as_tree.rb:393:in `build_hash_tree'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/bundler/gems/closure_tree-7bf33728b625/lib/closure_tree/acts_as_tree.rb:94:in `hash_tree'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/activerecord-3.2.9/lib/active_record/relation/delegation.rb:14:in `block in hash_tree'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/activerecord-3.2.9/lib/active_record/relation.rb:241:in `block in scoping'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/activerecord-3.2.9/lib/active_record/scoping.rb:98:in `with_scope'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/activerecord-3.2.9/lib/active_record/relation.rb:241:in `scoping'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/activerecord-3.2.9/lib/active_record/relation/delegation.rb:14:in `hash_tree'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/activerecord-3.2.9/lib/active_record/associations/collection_proxy.rb:100:in `method_missing'
        from (irb):6
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/railties-3.2.9/lib/rails/commands/console.rb:47:in `start'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/railties-3.2.9/lib/rails/commands/console.rb:8:in `start'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/zeus-0.12.0/lib/zeus/rails.rb:117:in `console'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/zeus-0.12.0/lib/zeus.rb:105:in `block in command'
... 8 levels...
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/zeus-0.12.0/lib/zeus.rb:61:in `go'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/zeus-0.12.0/lib/zeus.rb:67:in `block (3 levels) in go'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/zeus-0.12.0/lib/zeus.rb:67:in `fork'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/zeus-0.12.0/lib/zeus.rb:67:in `block (2 levels) in go'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/zeus-0.12.0/lib/zeus.rb:63:in `each'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/zeus-0.12.0/lib/zeus.rb:63:in `block in go'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/zeus-0.12.0/lib/zeus.rb:61:in `loop'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/zeus-0.12.0/lib/zeus.rb:61:in `go'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/zeus-0.12.0/lib/zeus.rb:67:in `block (3 levels) in go'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/zeus-0.12.0/lib/zeus.rb:67:in `fork'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/zeus-0.12.0/lib/zeus.rb:67:in `block (2 levels) in go'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/zeus-0.12.0/lib/zeus.rb:63:in `each'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/zeus-0.12.0/lib/zeus.rb:63:in `block in go'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/zeus-0.12.0/lib/zeus.rb:61:in `loop'
        from /Users/kurko/.rbenv/versions/1.9.3-p194-perf/lib/ruby/gems/1.9.1/gems/zeus-0.12.0/lib/zeus.rb:61:in `go'
        from -e:1:in `<main>'

Get ancestors in a callback

Hello,

I'm using closure_tree 4.0.1 with rails 3.0 and ruby 1.9.3

In the model I use to act_as_tree, I need to trigger an after_create callback when a leaf is created. This callback needs the ancestors of the current object to do some operation.

Unfortunately, I cant access the ancestors in the after_create because it seems that the hierarchie of the newly created object is written in the table after the callbacks.

Would you have any idea how to fix this issue ?

Do not processed situation when unexisted parent id passed

I pass unexisted parent id (1)

> cc = Comment.new(parent_id: 1)
 => #<Comment id: nil, parent_id: 1, created_at: nil, updated_at: nil> 
> cc.parent
  Comment Load (1.1ms)  SELECT "comments".* FROM "comments" WHERE "comments"."id" = $1 ORDER BY "comments"."id" ASC LIMIT 1  [["id", 1]]
 => nil 
> cc.save
   (0.8ms)  BEGIN
  SQL (5.6ms)  INSERT INTO "comments" ("created_at", "parent_id", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["created_at", Fri, 09 Aug 2013 13:56:01 UTC +00:00], ["parent_id", 1], ["updated_at", Fri, 09 Aug 2013 13:56:01 UTC +00:00]]
   (1.0ms)  SELECT pg_try_advisory_lock(2085799232), 1376056561.717587
  SQL (0.9ms)  INSERT INTO "comment_hierarchies" ("ancestor_id", "descendant_id", "generations") VALUES ($1, $2, $3)  [["ancestor_id", 20621], ["descendant_id", 20621], ["generations", 0]]
   (1.0ms)   INSERT INTO "comment_hierarchies"
 (ancestor_id, descendant_id, generations)
 SELECT x.ancestor_id, 20621, x.generations + 1
 FROM "comment_hierarchies" x
 WHERE x.descendant_id = 1

  Comment Load (10.3ms)  SELECT "comments".* FROM "comments" WHERE "comments"."parent_id" = $1 ORDER BY created_at  [["parent_id", 20621]]
   (0.7ms)  SELECT pg_advisory_unlock(2085799232), 1376056561.764168
   (1.8ms)  COMMIT
 => true 
> cc.parent
 => nil 
> cc.parent_id
 => 1 

But parent_id and record in hierarchies table was added.

[QUESTION] Scope on multiple trees

Hello, I've been trying to solve this problem where I'd like to search for a node across a few different trees. In essence, something similar to calling descendants, but works with multiple trees at once in 1 query. Has anyone had any success in doing this with closure_tree?

Here's a quick example:

A => [B]
C => [D, Z]
E => [F, G, H]

>> Node.subtrees_for([A, C]).find(D)
=> D

Thank you.

License missing from gemspec

Some companies will only use gems with a certain license.
The canonical and easy way to check is via the gemspec
via e.g.

spec.license = 'MIT'
# or
spec.licenses = ['MIT', 'GPL-2']

There is even a License Finder to help companies ensure all gems they use
meet their licensing needs. This tool depends on license information being available in the gemspec.
Including a license in your gemspec is a good practice, in any case.

How did I find you?

I'm using a script to collect stats on gems, originally looking for download data, but decided to collect licenses too,
and make issues for missing ones as a public service :)
https://gist.github.com/bf4/5952053#file-license_issue-rb-L13 So far it's going pretty well

Hierarchy class equals method unnecessarily loads ancestor and descendants

The hierarchy class' == is checking equality on the ancestor and descendant associations (acts_as_tree.rb:39) which causes those objects to be unnecessarily loaded when checking equality. Can the equality check instead compare the ancestor_id and descendant_id?

This is especially noticeable during eager loading. For example, running the following query in my app:

Category.where(id: ids).includes(:self_and_ancestors)

Runs the following SQL statements:

Category Load (0.9ms)  SELECT "categories".* FROM "categories" WHERE "categories"."organization_id" = 1 AND "categories"."id" IN (20, 22)
CategoryHierarchy Load (0.5ms)  SELECT "category_hierarchies".* FROM "category_hierarchies" WHERE "category_hierarchies"."descendant_id" IN (20, 22) ORDER BY "category_hierarchies".generations asc
Category Load (0.6ms)  SELECT "categories".* FROM "categories" WHERE "categories"."organization_id" = 1 AND "categories"."id" = 19 LIMIT 1
Category Load (0.4ms)  SELECT "categories".* FROM "categories" WHERE "categories"."organization_id" = 1 AND "categories"."id" = 20 LIMIT 1
Category Load (0.3ms)  SELECT "categories".* FROM "categories" WHERE "categories"."organization_id" = 1 AND "categories"."id" = 18 LIMIT 1
Category Load (0.3ms)  SELECT "categories".* FROM "categories" WHERE "categories"."organization_id" = 1 AND "categories"."id" = 22 LIMIT 1
Category Load (0.5ms)  SELECT "categories".* FROM "categories" WHERE "categories"."organization_id" = 1 AND "categories"."id" = 18 LIMIT 1
Category Load (0.3ms)  SELECT "categories".* FROM "categories" WHERE "categories"."organization_id" = 1 AND "categories"."id" = 19 LIMIT 1

If I change the equal implementation to compare ids, it only runs the following:

Category Load (0.8ms)  SELECT "categories".* FROM "categories" WHERE "categories"."organization_id" = 1 AND "categories"."id" IN (20, 22)
CategoryHierarchy Load (0.4ms)  SELECT "category_hierarchies".* FROM "category_hierarchies" WHERE "category_hierarchies"."descendant_id" IN (20, 22) ORDER BY "category_hierarchies".generations asc
Category Load (0.5ms)  SELECT "categories".* FROM "categories" WHERE "categories"."organization_id" = 1 AND "categories"."id" IN (20, 19, 18, 22)

I'll work on putting together a pull request (although it's a pretty easy fix).

Support default Rails transactions

As per Rails docs #save and #destroy are wrapped into a single transaction by default. This way you don't need to handle transactions when affecting multiple related models.

closure_tree does not extend this on its operations, specifically when moving nodes around. Here's what I see when adding a new node as children of another:

# assume the parent has been already persisted
child = Tag.new(:name => 'Child')
child.save
parent.children << child
BEGIN
-- INSERT THE CHILD (parent_id is NULL)
-- INSERT TO THE HIERARCHY everything related to the child (good!)
COMMIT -- :(

BEGIN
-- UPDATE parent_id
-- DELETE FROM THE HIERARCHY everything related to the child
-- INSERT TO THE HIERARCHY everything related to the child
COMMIT

Subtree ancestry hash

Arrange a tree or part of it into an ordered hash is a piece a closure_tree user will never regret to have.

The Ancestry project approaches to it in a very useful way.

find_or_create_by attributes not working

Me again, with another weird edge case issue:

In my app, our hierarchical tags are scoped to a particular client and we indicate this with a 'client_name' field in our TagDefinition object.

I'm calling find_or_create_by_path thusly

TagDefinition.find_or_create_by_path(hierarchies, {'client_name' => client_name, 'context' => TagDefinition::HIERARCHY_CONTEXT})

where 'hierarchies' is an array of tag_definition names. The problem is this - every single one of our clients has a root tag called "All". When I run the above snippet for a hierarchies value of ['All','North','South'] for a client_name of 'aperture_science', closure tree happily finds the root tag 'All' - for another client, 'acme', and then creates all the other tags with the incorrect tag as the root.

The problem is this:

In both the class and instance methods of find_or_create_by_path, you accept a hash of attributes that get passed to active record. This is all groovy, except that the hash of attributes is only honored in the insert/update, NOT in the where clause.

I updated my fork https://github.com/juddblair/closure_tree with a quick and dirty fix (merged in the attributes hash before the where clause) and ran it against our app, seemed to fix the problem.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.