I'm using the ancestry gem to structure some groups in a tree. At the same time I'm using acts_as_list to keep groups at the same tree level in a sorted list. Given the following model:
class Group < ActiveRecord::Base
acts_as_tree
acts_as_list :scope => "ancestry"
named_scope :parentable, :conditions => "NOT type = 'PriceGroup'"
named_scope :without, lambda { |ids| { :conditions => ['id NOT IN (?)', ids] }}
default_scope :order => "groups.position ASC, groups.name ASC"
end
This worked pretty much as intended, eg I use @group.path
to generate a breadcrumb navigation at the top of the admin interface. The generated SQL is okay, the breadcrumbs are sorted by tree depth as they should. At least this is true for the development environment.
In production it looks completely different: Tracing the generated SQL I found that not ancestry's path
is generating the result order but instead my default_scope
takes over.
So I fixed my model to ignore the default scope by overwriting path
:
# remove default scope to not change path sorting
def path
self.class.send :with_exclusive_scope do
super
end
end
But while this removed the position scoping from my default_scope
in development it still is completely ignored in production. Tracing the SQL in production, I don't see ancestry's depth ordering, but instead the position ordering from my default_scope
.
Update: Since my original idea of "patching" the path
method was somewhat silly (knock knock: it's not inherited, it's dynamically defined), I tried the following still to no avail:
# remove default scope to not change path sorting
def path_with_exclusive_scope
self.class.send :with_exclusive_scope do
path_without_exclusive_scope
end
end
alias_method_chain :path, :exclusive_scope
When calling path
in development the generated SQL is as follows:
SELECT *
FROM "groups"
WHERE ("groups"."id" IN (5,64))
ORDER BY (case when ancestry is null then 0 else 1 end), ancestry
Compared to that here's the generated SQL in production:
SELECT *
FROM `groups`
WHERE (`groups`.`id` IN (8,49))
ORDER BY groups.position ASC, groups.name ASC
Development uses SQLite where production uses MySQL - but I don't think that is the crucial difference here.