Permalink
Browse files

Merge branch 'master' of github.com:stefankroes/ancestry

  • Loading branch information...
2 parents 31ad369 + 495cda6 commit 469fe34bb35c05d628f9e122122ac73dce3cc0f7 @stefankroes stefankroes committed Nov 19, 2010
Showing with 133 additions and 85 deletions.
  1. +7 −4 README.rdoc
  2. +2 −3 ancestry.gemspec
  3. +1 −1 lib/ancestry/has_ancestry.rb
  4. +23 −11 lib/ancestry/instance_methods.rb
  5. +9 −4 test/environment.rb
  6. +91 −62 test/has_ancestry_test.rb
View
@@ -15,7 +15,7 @@ To apply Ancestry to any ActiveRecord model, follow these simple steps:
- Install required gems: <b>bundle install</b>
2. Add ancestry column to your table
- - Create migration: <b>./script/generate migration add_ancestry_to_[table] ancestry:string</b>
+ - Create migration: <b>rails g migration add_ancestry_to_[table] ancestry:string</b>
- Add index to migration: <b>add_index [table], :ancestry</b> (UP) / <b>remove_index [table], :ancestry</b> (DOWN)
- Migrate your database: <b>rake db:migrate</b>
@@ -161,7 +161,7 @@ The arrange method takes ActiveRecord find options. If you want your hashes to b
Most current tree plugins use a parent_id column (has_ancestry, awesome_nested_set, better_nested_set, acts_as_nested_set). With ancestry its easy to migrate from any of these plugins, to do so, use the build_ancestry_from_parent_ids! method on your ancestry model. These steps provide a more detailed explanation:
1. Add ancestry column to your table
- - Create migration: <b>./script/generate migration add_ancestry_to_[table] ancestry:string</b>
+ - Create migration: <b>rails g migration add_ancestry_to_[table] ancestry:string</b>
- Add index to migration: <b>add_index [table], :ancestry</b> (UP) / <b>remove_index [table], :ancestry</b> (DOWN)
- Migrate your database: <b>rake db:migrate</b>
@@ -185,7 +185,7 @@ Most current tree plugins use a parent_id column (has_ancestry, awesome_nested_s
- Check if all your data is intact and all tests pass
6. Drop parent_id column:
- - Create migration: <b>./script/generate migration remove_parent_id_from_[table]</b>
+ - Create migration: <b>rails g migration remove_parent_id_from_[table]</b>
- Add to migration: <b>remove_column [table], :parent_id</b> (UP) / <b>add_column [table], :parent_id, :integer</b> (DOWN)
- Migrate your database: <b>rake db:migrate</b>
@@ -228,8 +228,11 @@ The materialised path pattern requires Ancestry to use a 'like' condition in ord
= Version history
-The latest and recommended version of ancestry is 1.2.2. The three numbers of each version numbers are respectively the major, minor and patch versions. We started with major version 1 because it looks so much better and ancestry was already quite mature and complete when it was published. The major version is only bumped when backwards compatibility is broken. The minor version is bumped when new features are added. The patch version is bumped when bugs are fixed.
+The latest version of ancestry is recommended. The three numbers of each version numbers are respectively the major, minor and patch versions. We started with major version 1 because it looks so much better and ancestry was already quite mature and complete when it was published. The major version is only bumped when backwards compatibility is broken. The minor version is bumped when new features are added. The patch version is bumped when bugs are fixed.
+- Version 1.2.3 (2010-10-28)
+ - Fixed error with determining ActiveRecord version
+ - Added option to specify :primary_key_format (thanks goes to rolftimmermans)
- Version 1.2.2 (2010-10-24)
- Fixed all deprecation warnings for rails 3.0.X
- Added :report option to check_ancestry_integrity!
View
@@ -3,8 +3,7 @@ Gem::Specification.new do |s|
s.description = 'Organise ActiveRecord model into a tree structure'
s.summary = 'Ancestry allows the records of a ActiveRecord model to be organised in a tree structure, using a single, intuitively formatted database column. It exposes all the standard tree structure relations (ancestors, parent, root, children, siblings, descendants) and all of them can be fetched in a single sql query. Additional features are named_scopes, integrity checking, integrity restoration, arrangement of (sub)tree into hashes and different strategies for dealing with orphaned records.'
- s.version = '1.2.2'
- s.date = '2010-10-24'
+ s.version = '1.2.3'
s.author = 'Stefan Kroes'
s.email = 's.a.kroes@gmail.com'
@@ -24,4 +23,4 @@ Gem::Specification.new do |s|
]
s.add_dependency 'activerecord', '>= 2.2.2'
-end
+end
@@ -39,7 +39,7 @@ def has_ancestry options = {}
# Save ActiveRecord version
self.cattr_accessor :rails_3
- self.rails_3 = defined?(ActiveRecord::VERSION) and ActiveRecord::VERSION::MAJOR >= 3
+ self.rails_3 = defined?(ActiveRecord::VERSION) && ActiveRecord::VERSION::MAJOR >= 3
# Workaround to support Rails 2
scope_method = if rails_3 then :scope else :named_scope end
@@ -18,7 +18,7 @@ def update_descendants_with_new_ancestry
descendant.update_attribute(
self.base_class.ancestry_column,
descendant.read_attribute(descendant.class.ancestry_column).gsub(
- /^#{self.child_ancestry}/,
+ /^#{self.child_ancestry}/,
if read_attribute(self.class.ancestry_column).blank? then id.to_s else "#{read_attribute self.class.ancestry_column }/#{id}" end
)
)
@@ -55,7 +55,7 @@ def apply_orphan_strategy
end
end
end
-
+
# The ancestry value for this record's children
def child_ancestry
# New records cannot have children
@@ -66,7 +66,7 @@ def child_ancestry
# Ancestors
def ancestor_ids
- read_attribute(self.base_class.ancestry_column).to_s.split('/').map(&:to_i)
+ read_attribute(self.base_class.ancestry_column).to_s.split('/').map { |id| cast_primary_key(id) }
end
def ancestor_conditions
@@ -76,7 +76,7 @@ def ancestor_conditions
def ancestors depth_options = {}
self.base_class.scope_depth(depth_options, depth).ordered_by_ancestry.scoped :conditions => ancestor_conditions
end
-
+
def path_ids
ancestor_ids + [id]
end
@@ -88,11 +88,11 @@ def path_conditions
def path depth_options = {}
self.base_class.scope_depth(depth_options, depth).ordered_by_ancestry.scoped :conditions => path_conditions
end
-
+
def depth
ancestor_ids.size
end
-
+
def cache_depth
write_attribute self.base_class.depth_cache_column, depth
end
@@ -181,7 +181,7 @@ def descendants depth_options = {}
def descendant_ids depth_options = {}
descendants(depth_options).all(:select => self.base_class.primary_key).collect(&self.base_class.primary_key.to_sym)
end
-
+
# Subtree
def subtree_conditions
["#{self.base_class.primary_key} = ? or #{self.base_class.ancestry_column} like ? or #{self.base_class.ancestry_column} = ?", self.id, "#{child_ancestry}/%", child_ancestry]
@@ -194,20 +194,20 @@ def subtree depth_options = {}
def subtree_ids depth_options = {}
subtree(depth_options).all(:select => self.base_class.primary_key).collect(&self.base_class.primary_key.to_sym)
end
-
+
# Callback disabling
def without_ancestry_callbacks
@disable_ancestry_callbacks = true
yield
@disable_ancestry_callbacks = false
end
-
+
def ancestry_callbacks_disabled?
!!@disable_ancestry_callbacks
end
-
+
private
-
+
# Workaround to support Rails 2
def add_error_to_base error
if rails_3
@@ -216,5 +216,17 @@ def add_error_to_base error
errors.add_to_base error
end
end
+
+ def cast_primary_key(key)
+ if primary_key_type == :string
+ key
+ else
+ key.to_i
+ end
+ end
+
+ def primary_key_type
+ @primary_key_type ||= column_for_attribute(self.class.primary_key).type
+ end
end
end
View
@@ -10,13 +10,15 @@ def self.setup
ActiveRecord::Base.logger
ActiveRecord::Base.establish_connection YAML.load(File.open(File.join(File.dirname(__FILE__), 'database.yml')).read)[ENV['db'] || 'sqlite3']
end
-
+
def self.with_model options = {}
depth = options.delete(:depth) || 0
width = options.delete(:width) || 0
extra_columns = options.delete(:extra_columns)
-
- ActiveRecord::Base.connection.create_table 'test_nodes' do |table|
+ primary_key_type = options.delete(:primary_key_type) || :default
+
+ ActiveRecord::Base.connection.create_table 'test_nodes', :id => (primary_key_type == :default) do |table|
+ table.string :id, :null => false if primary_key_type == :string
table.string options[:ancestry_column] || :ancestry
table.integer options[:depth_cache_column] || :ancestry_depth if options[:cache_depth]
extra_columns.each do |name, type|
@@ -29,6 +31,9 @@ def self.with_model options = {}
(class << model; self; end).send :define_method, :model_name do; Struct.new(:human, :underscore).new 'TestNode', 'test_node'; end
const_set 'TestNode', model
+ if primary_key_type == :string
+ model.before_create { self.id = ActiveSupport::SecureRandom.hex(10) }
+ end
model.send :set_table_name, 'test_nodes'
model.has_ancestry options unless options.delete(:skip_ancestry)
@@ -42,7 +47,7 @@ def self.with_model options = {}
remove_const "TestNode"
end
end
-
+
def self.create_test_nodes model, depth, width, parent = nil
unless depth == 0
Array.new width do
Oops, something went wrong.

0 comments on commit 469fe34

Please sign in to comment.