/
order.rb
146 lines (118 loc) · 3.41 KB
/
order.rb
1
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
module Administrate
class Order
def initialize(attribute = nil, direction = nil, association_attribute: nil)
@attribute = attribute
@direction = sanitize_direction(direction)
@association_attribute = association_attribute
end
def apply(relation)
return order_by_association(relation) unless
reflect_association(relation).nil?
order = relation.arel_table[attribute].public_send(direction)
return relation.reorder(order) if
column_exist?(relation, attribute)
relation
end
def ordered_by?(attr)
attr.to_s == attribute.to_s
end
def order_params_for(attr)
{
order: attr,
direction: reversed_direction_param_for(attr)
}
end
attr_reader :direction
private
attr_reader :attribute, :association_attribute
def sanitize_direction(direction)
%w[asc desc].include?(direction.to_s) ? direction.to_sym : :asc
end
def reversed_direction_param_for(attr)
if ordered_by?(attr)
opposite_direction
else
:asc
end
end
def opposite_direction
(direction == :asc) ? :desc : :asc
end
def order_by_association(relation)
case relation_type(relation)
when :has_many
order_by_count(relation)
when :belongs_to
order_by_belongs_to(relation)
when :has_one
order_by_has_one(relation)
else
relation
end
end
def order_by_count(relation)
klass = reflect_association(relation).klass
query = klass.arel_table[klass.primary_key].count.public_send(direction)
relation
.left_joins(attribute.to_sym)
.group(:id)
.reorder(query)
end
def order_by_belongs_to(relation)
if ordering_by_association_column?(relation)
order_by_attribute(relation)
else
order_by_id(relation)
end
end
def order_by_has_one(relation)
if ordering_by_association_column?(relation)
order_by_attribute(relation)
else
order_by_association_id(relation)
end
end
def order_by_attribute(relation)
relation.joins(
attribute.to_sym
).reorder(order_by_attribute_query)
end
def order_by_id(relation)
relation.reorder(order_by_id_query(relation))
end
def order_by_association_id(relation)
relation.reorder(order_by_association_id_query)
end
def ordering_by_association_column?(relation)
association_attribute &&
column_exist?(
reflect_association(relation).klass, association_attribute.to_sym
)
end
def column_exist?(table, column_name)
table.columns_hash.key?(column_name.to_s)
end
def order_by_id_query(relation)
relation.arel_table[foreign_key(relation)].public_send(direction)
end
def order_by_association_id_query
Arel::Table.new(association_table_name)[:id].public_send(direction)
end
def order_by_attribute_query
table = Arel::Table.new(association_table_name)
table[association_attribute].public_send(direction)
end
def relation_type(relation)
reflect_association(relation).macro
end
def reflect_association(relation)
relation.klass.reflect_on_association(attribute.to_s)
end
def foreign_key(relation)
reflect_association(relation).foreign_key
end
def association_table_name
attribute.tableize
end
end
end