ruby-on-railsrubyacts-as-tree

Are ActiveRecord associations valid before committing to database?


I have a model which uses acts-as-tree. For example:

class CartoonCharacter < ActiveRecord::Base
  acts_as_tree
end

Acts as tree has these associations:

class ActsAsTree
  belongs_to :parent
  has_many :children
end

From script/console I am building my tree, saving nothing until the entire tree is constructed. The trouble I am having is that prior to committing to the database I am unable to successfully navigate the tree. Calls to #parent and #sibling produce questionable results. I can only assume I'm missing something.

fred=CartoonCharacter.new(:name=>'Fred')
fred.children.build(:name => 'BamBam')
pebbles = fred.children.build(:name => 'Pebbles')

fred.children #=> [BamBam, Pebbles]
fred.children.last.parent #=> nil --- why not Fred?
pebbles.siblings #=> [completely unrelated records from db??]

I am guessing this has something to do with the way associations are handled. I would have imagined that in-memory ActiveRecord structures would be completely navigable, but they don't seem to be. From forcing logging to the console I've sometimes noted that navigating across associations causes database access. This makes it difficult to know how to circumnavigate associations. (I looked briefly into query caching.) How are others handling this? Or are you always committing records and their relations as you go? This is puzzling.


EDIT:

What appears to solve this problem is to set both relations at the same time. That is, the missing piece was:

pebbles.parent = fred
bambam.parent = fred

Is this by design? That is, are we always expected to set both parts of a reciprocal relationship?


EDIT:

Related question


Solution

  • Are you using the acts_as_tree plugin? -- http://github.com/rails/acts_as_tree/tree/master

    It will work the way you want/expect.

    If you're rolling this data structure by yourself, your associations as described in the OP are not complete--they're referring to different foreign keys.

    belongs_to :parent  # parent_id field in this model
    has_many :children  # child_id field in the child models
    

    So currently, there are two different associations between pairs of instances. That's why you're having to make two assignment statements.

    Instead of the above, something more like

    belongs_to :parent, :class_name => "CartoonCharacter", 
      :foreign_key => :tree_key
    
    has_many :children, :class_name => "CartoonCharacter",
      :foreign_key => :tree_key
    

    Larry