Class: ActiveRecord::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/smart_order.rb

Class Method Summary collapse

Class Method Details

.smart_order(order, desc = nil) ⇒ Object



2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/smart_order.rb', line 2

def self.smart_order(order, desc = nil)
  # capture the sort column and whether sorting should be reversed (descending)
  key, inline_desc = order.sub(/( desc)$/i,''), !!$1
  desc = inline_desc if desc.nil?
  last_class = self
  joins = []
  conditions = []
  sum_column = nil

  while matches = key.match(/^(?<first>[^\.]*)\.(?<rest>.*)$/)
    first = matches[:first]
    rest = matches[:rest]

    if first.match(/^(.*)=(.*)$/)
      conditions << last_class.arel_table[$1].eq($2)
    elsif association = last_class.reflect_on_association(first.to_sym)
      joins << first
      last_class = association.klass
    elsif rest == 'sum'
      sum_column=first
    end
    key = rest
  end

  scope = scoped
  if association = last_class.reflect_on_association(key.to_sym)
    joins << key
    last_class = association.klass
    key = last_class.default_order_column
  end

  unless joins.empty?
    join = Squeel::Nodes::Join.new(joins.shift.to_sym).outer
    while nextjoin = joins.shift
      join = join.send(nextjoin.to_sym).outer
    end
    scope = scope.joins join
  end

  conditions.each do |condition|
    scope = scope.where condition
  end

  order =
    if key == 'sum' or key == 'count'
      group_bys = column_names.map{|c| "#{table_name}.#{c}"}
      scope = scope.group(group_bys)
      if key == 'count'
        "COUNT(#{last_class.table_name}.id)"
      else
        "SUM(#{last_class.table_name}.#{sum_column})"
      end
    elsif last_class.respond_to?(special_method= "order_by_#{key}")
      last_class.send special_method
    else
      "#{last_class.table_name}.#{key}"
    end

  order += " DESC" if desc
  scope.order(order)
end