Skip to content


Subversion checkout URL

You can clone with
Download ZIP


Allow non-integer primary keys. #26

2 commits merged into from

2 participants


Hi! Thanks for making a great plugin!

While using it on one of my projects, I struggled with making Ancestry work with non-integer primary keys (e.g. UUIDs). It is pretty much impossible to change this behaviour without copying large chunks of code, so here's a set of patches (one code + test, one documentation) that will allow a user to specify a primary key format as a regular expression. Tests continue to run, and it seems to work fine on my project so far.

Thanks for considering including this feature! Please let me know if you have any feedback.

Kind regards,

Rolf Timmermans


Great! I merged your changed into the repository.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 25, 2010
  1. Allow specification of primary key format, to facility non-integer pr…

    Rolf Timmermans authored
    …imary keys.
  2. Documentation for :primary_key_format.

    Rolf Timmermans authored
This page is out of date. Refresh to see the latest.
2  README.rdoc
@@ -80,6 +80,8 @@ The has_ancestry methods supports the following options:
- Migrate: add_column [table], :ancestry_depth, :integer, :default => 0
- Build cache: TreeNode.rebuild_depth_cache!
:depth_cache_column Pass in a symbol to store depth cache in a different column
+ :primary_key_format Supply a regular expression that matches the format of your primary key.
+ By default, primary keys only match integers ([0-9]+).
= (Named) Scopes
5 lib/ancestry/has_ancestry.rb
@@ -7,7 +7,7 @@ def has_ancestry options = {}
# Check options
raise"Options for has_ancestry must be in a hash.") unless options.is_a? Hash
options.each do |key, value|
- unless [:ancestry_column, :orphan_strategy, :cache_depth, :depth_cache_column].include? key
+ unless [:ancestry_column, :orphan_strategy, :cache_depth, :depth_cache_column, :primary_key_format].include? key
raise"Unknown option for has_ancestry: #{key.inspect} => #{value.inspect}.")
@@ -31,7 +31,8 @@ def has_ancestry options = {}
self.base_class = self
# Validate format of ancestry column value
- validates_format_of ancestry_column, :with => /\A[0-9]+(\/[0-9]+)*\Z/, :allow_nil => true
+ key_format = options[:primary_key_format] || /[0-9]+/
+ validates_format_of ancestry_column, :with => /\A#{key_format.source}(\/#{key_format.source})*\Z/, :allow_nil => true
# Validate that the ancestor ids don't include own id
validate :ancestry_exclude_self
12 test/has_ancestry_test.rb
@@ -213,6 +213,18 @@ def test_ancestry_column_validation
node.valid?; assert !node.errors[model.ancestry_column].blank?
+ AncestryTestDatabase.with_model :primary_key_format => /[0-9a-z]+/ do |model|
+ node = model.create
+ ['xk7', '9x1/l4n', 'r1c/4z9/8ps', nil].each do |value|
+ node.send :write_attribute, model.ancestry_column, value
+ node.valid?; assert node.errors[model.ancestry_column].blank?
+ end
+ ['s9a/xk2/', '/s92/d92', 'X', 'X/Y', 'S23', '/xk2'].each do |value|
+ node.send :write_attribute, model.ancestry_column, value
+ node.valid?; assert !node.errors[model.ancestry_column].blank?
+ end
+ end
def test_descendants_move_with_node
Something went wrong with that request. Please try again.