私はそれを少し違ったやり方で行うことができましたが、これはあなたの状況ではうまくいかないかもしれません。私は既存のコードをリファクタリングしていて、深刻なデータベースの移行をしたくありませんでした。
リーフクラスとノードクラスを別々にしたかったのです。どちらもツリークラスから継承します。
ClassMethodsに2つの関数を追加しましたvendor/plugins/acts_as_tree/lib/active_record/acts/tree.rb
:
# Configuration options are:
#
# * <tt>foreign_key</tt> - specifies the column name to use for tracking of the tree (default: +parent_id+)
# * <tt>order</tt> - makes it possible to sort the children according to this SQL snippet.
# * <tt>counter_cache</tt> - keeps a count in a +children_count+ column if set to +true+ (default: +false+).
# * <tt>leaf_class_name</tt> - leaf class subtype of base tree class
# * <tt>node_class_name</tt> - node class subtype of base tree class
def acts_as_tree_node(options = {})
configuration = { :foreign_key => "parent_id", :order => nil, :counter_cache => nil, :node_class_name => 'Node', :leaf_class_name => 'Leaf' }
configuration.update(options) if options.is_a?(Hash)
belongs_to :parent, :class_name => configuration[:node_class_name], :foreign_key => configuration[:foreign_key], :counter_cache => configuration[:counter_cache]
#has_many :children, :foreign_key => configuration[:foreign_key], :order => configuration[:order], :dependent => :destroy
class_eval <<-EOV
has_many :child_nodes, :class_name => '#{configuration[:node_class_name]}', :foreign_key => "#{configuration[:foreign_key]}", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}}, :dependent => :destroy
has_many :child_leaves, :class_name => '#{configuration[:leaf_class_name]}', :foreign_key => "#{configuration[:foreign_key]}", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}}, :dependent => :destroy
include ActiveRecord::Acts::Tree::InstanceMethods
def self.roots
find(:all, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}})
end
def self.root
find(:first, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}})
end
EOV
end
# Configuration options are:
#
# * <tt>foreign_key</tt> - specifies the column name to use for tracking of the tree (default: +parent_id+)
# * <tt>order</tt> - makes it possible to sort the children according to this SQL snippet.
# * <tt>counter_cache</tt> - keeps a count in a +children_count+ column if set to +true+ (default: +false+).
# * <tt>node_class_name</tt> - the class name of the node (subclass of the tree base)
def acts_as_tree_leaf(options = {})
configuration = { :foreign_key => "parent_id", :order => nil, :counter_cache => nil, :node_class_name => 'Node' }
configuration.update(options) if options.is_a?(Hash)
belongs_to :parent, :class_name => configuration[:node_class_name], :foreign_key => configuration[:foreign_key], :counter_cache => configuration[:counter_cache]
class_eval <<-EOV
include ActiveRecord::Acts::Tree::InstanceMethods
def self.roots
find(:all, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}})
end
def self.root
find(:first, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}})
end
EOV
end
次に、InstanceMethodsで、次の1つの関数を追加しました。
# Returns list of children, whether nodes or leaves.
#
# NOTE: Will not return both, because that would take two queries and
# order will not be preserved.
def children
child_leaves.count == 0 ? child_nodes : child_leaves
end
これはちょっとしたハックですが、すべてのノードにすべて1つのタイプのサブがあるので、私にとってはうまくいきます。このchildren
関数を試して、次のようなさまざまな動作を取得できます。
def children
child_nodes | child_leaves
end
ただし、それでも追加のクエリが必要になり、順序やスコープなどが失われます。
最後に、私のNodeクラスでは、
acts_as_tree_node :node_class_name => 'NodeMatrix', :leaf_class_name => 'LeafMatrix'
そして私のLeafクラスでは、次のようになります。
acts_as_tree_leaf :node_class_name => 'NodeMatrix'
これらは両方とも、純粋な仮想であるTreeMatrixから継承します(TreeMatrixとして実際にインスタンス化されるものはなく、単なる基本クラスです)。
繰り返しますが、これは非常にアプリケーション固有です。ただし、acts_as_treeを変更する方法がわかります。