From 5b573589aa649eb91169477bf59a5ec1a132119f Mon Sep 17 00:00:00 2001 From: Pedro Nascimento Date: Tue, 7 Feb 2017 17:36:27 -0200 Subject: [PATCH] Sort by default_sort on association class. This allows us to sort by these associations using a given attribute that uses name by default but can be overwritten by the static method default_sort on the associated class. --- lib/administrate/order.rb | 44 +++++++++++++++++++++++++++++ spec/lib/administrate/order_spec.rb | 28 ++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/lib/administrate/order.rb b/lib/administrate/order.rb index 85edcdcc90..941e4df00b 100644 --- a/lib/administrate/order.rb +++ b/lib/administrate/order.rb @@ -8,6 +8,8 @@ def initialize(attribute = nil, direction = nil) def apply(relation) if relation.columns_hash.keys.include?(attribute.to_s) relation.order(attribute => direction) + elsif association?(relation) + AssociationOrder.new(relation, attribute, direction).relation_with_order else relation end @@ -30,6 +32,12 @@ def order_params_for(attr) attr_reader :attribute + def association?(relation) + if relation.respond_to? :reflect_on_association + relation.reflect_on_association(attribute) + end + end + def reversed_direction_param_for(attr) if ordered_by?(attr) opposite_direction @@ -42,4 +50,40 @@ def opposite_direction direction.to_sym == :asc ? :desc : :asc end end + + class AssociationOrder + def initialize(relation, attribute, direction) + @relation = relation + @attribute = attribute + @direction = direction + end + + def relation_with_order + association ? relation.includes(association.name).order("#{association.plural_name}.#{order_name} #{direction_for_sql}") : relation + end + + def order_name + if association.klass.respond_to? :default_sort + association.klass.default_sort + else + :name + end + end + + def direction_for_sql + if direction.to_sym == :asc + "ASC" + else + "DESC" + end + end + + private + + def association + relation.reflect_on_association(attribute) + end + + attr_reader :relation, :attribute, :direction + end end diff --git a/spec/lib/administrate/order_spec.rb b/spec/lib/administrate/order_spec.rb index fbc98ab4f4..aa711348be 100644 --- a/spec/lib/administrate/order_spec.rb +++ b/spec/lib/administrate/order_spec.rb @@ -1,4 +1,5 @@ require "administrate/order" +require "rails_helper" describe Administrate::Order do describe "#apply" do @@ -51,6 +52,33 @@ expect(ordered).to eq(relation) end end + + context 'when `order` uses an association with no default_sort method' do + it 'orders by `name` on the associated record by default' do + order = Administrate::Order.new(:customer, :desc) + relation = Order.all + allow(relation).to receive(:order).and_return(relation) + + ordered = order.apply(relation) + + expect(relation).to have_received(:order).with('customers.name DESC') + expect(ordered).to eq(relation) + end + end + + context 'when `order` uses an association with a default_sort method' do + it 'orders by the attribute given in the default_sort method' do + order = Administrate::Order.new(:customer, :asc) + relation = Order.all + allow(relation).to receive(:order).and_return(relation) + allow(Customer).to receive(:default_sort).and_return(:updated_at) + + ordered = order.apply(relation) + + expect(relation).to have_received(:order).with('customers.updated_at ASC') + expect(ordered).to eq(relation) + end + end end describe "#ordered_by?" do