views:

246

answers:

0

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.