Skip to content

Commit

Permalink
Order attributes by association if it exists (#999)
Browse files Browse the repository at this point in the history
Adding an order clause to the relation for an associated
attribute was having no effect on the dashboard's sorting.
When the order is applied, the current relation will check
if the attribute is an association and reorder by count
on the attribute's id column or on the relation's
{attribute}_id column following the Rails convention
of naming FK columns. The relation order method was
changed to reorder to override any default scoping
that may exist for the relation.

Fixes #471.
  • Loading branch information
rnice01 authored and nickcharlton committed Dec 19, 2017
1 parent 12a40dd commit 218cb9d
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 14 deletions.
43 changes: 38 additions & 5 deletions lib/administrate/order.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ def initialize(attribute = nil, direction = nil)
end

def apply(relation)
if relation.columns_hash.keys.include?(attribute.to_s)
relation.order("#{attribute} #{direction}")
else
relation
end
return order_by_association(relation) unless
reflect_association(relation).nil?

return relation.reorder("#{attribute} #{direction}") if
relation.columns_hash.keys.include?(attribute.to_s)

relation
end

def ordered_by?(attr)
Expand Down Expand Up @@ -41,5 +43,36 @@ def reversed_direction_param_for(attr)
def opposite_direction
direction.to_sym == :asc ? :desc : :asc
end

def order_by_association(relation)
return order_by_count(relation) if has_many_attribute?(relation)

return order_by_id(relation) if belongs_to_attribute?(relation)

relation
end

def order_by_count(relation)
relation.
left_joins(attribute.to_sym).
group(:id).
reorder("COUNT(#{attribute}.id) #{direction}")
end

def order_by_id(relation)
relation.reorder("#{attribute}_id #{direction}")
end

def has_many_attribute?(relation)
reflect_association(relation).macro == :has_many
end

def belongs_to_attribute?(relation)
reflect_association(relation).macro == :belongs_to
end

def reflect_association(relation)
relation.klass.reflect_on_association(attribute.to_s)
end
end
end
57 changes: 48 additions & 9 deletions spec/lib/administrate/order_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
it "doesn't sort the resources" do
order = Administrate::Order.new(nil, :desc)
relation = relation_with_column(:id)
allow(relation).to receive(:order).and_return(relation)
allow(relation).to receive(:reorder).and_return(relation)

ordered = order.apply(relation)

expect(relation).not_to have_received(:order)
expect(relation).not_to have_received(:reorder)
expect(ordered).to eq(relation)
end
end
Expand All @@ -19,11 +19,11 @@
it "ignores the order" do
order = Administrate::Order.new(:foo)
relation = relation_with_column(:id)
allow(relation).to receive(:order).and_return(relation)
allow(relation).to receive(:reorder).and_return(relation)

ordered = order.apply(relation)

expect(relation).not_to have_received(:order)
expect(relation).not_to have_received(:reorder)
expect(ordered).to eq(relation)
end
end
Expand All @@ -32,22 +32,52 @@
it "orders by the column" do
order = Administrate::Order.new(:name, :asc)
relation = relation_with_column(:name)
allow(relation).to receive(:order).and_return(relation)
allow(relation).to receive(:reorder).and_return(relation)

ordered = order.apply(relation)

expect(relation).to have_received(:order).with("name asc")
expect(relation).to have_received(:reorder).with("name asc")
expect(ordered).to eq(relation)
end

it "honors the `direction` argument" do
order = Administrate::Order.new(:name, :desc)
relation = relation_with_column(:name)
allow(relation).to receive(:order).and_return(relation)
allow(relation).to receive(:reorder).and_return(relation)

ordered = order.apply(relation)

expect(relation).to have_received(:order).with("name desc")
expect(relation).to have_received(:reorder).with("name desc")
expect(ordered).to eq(relation)
end
end

context "when relation has_many association" do
it "orders the column by count" do
order = Administrate::Order.new(:name)
relation = relation_with_association(:has_many)
allow(relation).to receive(:reorder).and_return(relation)
allow(relation).to receive(:left_joins).and_return(relation)
allow(relation).to receive(:group).and_return(relation)

ordered = order.apply(relation)

expect(relation).to have_received(:left_joins).with(:name)
expect(relation).to have_received(:group).with(:id)
expect(relation).to have_received(:reorder).with("COUNT(name.id) asc")
expect(ordered).to eq(relation)
end
end

context "when relation has belongs_to association" do
it "orders by id" do
order = Administrate::Order.new(:name)
relation = relation_with_association(:belongs_to)
allow(relation).to receive(:reorder).and_return(relation)

ordered = order.apply(relation)

expect(relation).to have_received(:reorder).with("name_id asc")
expect(ordered).to eq(relation)
end
end
Expand Down Expand Up @@ -138,6 +168,15 @@
end

def relation_with_column(column)
double(columns_hash: { column.to_s => :column_info })
double(
klass: double(reflect_on_association: nil),
columns_hash: { column.to_s => :column_info },
)
end

def relation_with_association(association)
double(
klass: double(reflect_on_association: double(macro: association)),
)
end
end

0 comments on commit 218cb9d

Please sign in to comment.