Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable ordering the BelongsTo fields by using order option. #2208

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion app/controllers/administrate/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,21 @@ def records_per_page
end

def order
@order ||= Administrate::Order.new(sorting_attribute, sorting_direction)
@order ||= Administrate::Order.new(
sorting_attribute,
sorting_direction,
order_by_field(dashboard_attribute(sorting_attribute)),
)
end

def order_by_field(dashboard)
return unless dashboard.try(:options)

dashboard.options.fetch(:order, nil)
end

def dashboard_attribute(attribute)
dashboard.attribute_types[attribute.to_sym] if attribute
end

def sorting_attribute
Expand Down
38 changes: 33 additions & 5 deletions lib/administrate/order.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
module Administrate
class Order
def initialize(attribute = nil, direction = nil)
def initialize(attribute = nil, direction = nil, field = nil)
patrickgramatowski marked this conversation as resolved.
Show resolved Hide resolved
@attribute = attribute
@direction = sanitize_direction(direction)
@field = field
end

def apply(relation)
Expand All @@ -12,11 +13,15 @@ def apply(relation)
order = "#{relation.table_name}.#{attribute} #{direction}"

return relation.reorder(Arel.sql(order)) if
relation.columns_hash.keys.include?(attribute.to_s)
column_exist?(relation, attribute)

relation
end

def column_exist?(table, column_name)
table.columns_hash.key?(column_name.to_s)
end
patrickgramatowski marked this conversation as resolved.
Show resolved Hide resolved

def ordered_by?(attr)
attr.to_s == attribute.to_s
end
Expand All @@ -32,7 +37,7 @@ def order_params_for(attr)

private

attr_reader :attribute
attr_reader :attribute, :field

def sanitize_direction(direction)
%w[asc desc].include?(direction.to_s) ? direction.to_sym : :asc
Expand All @@ -53,7 +58,7 @@ def opposite_direction
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)
return order_by_attribute(relation) if belongs_to_attribute?(relation)

relation
end
Expand All @@ -68,7 +73,30 @@ def order_by_count(relation)
end

def order_by_id(relation)
relation.reorder("#{foreign_key(relation)} #{direction}")
relation.reorder(Arel.sql(order_by_id_query(relation)))
end

def order_by_attribute(relation)
return order_by_id(relation) unless field

relation.joins(
attribute.to_sym,
).reorder(Arel.sql(form_query(relation)))
end

def form_query(relation)
return order_by_attribute_query if
column_exist?(reflect_association(relation).klass, field.to_sym)

order_by_id_query(relation)
end
patrickgramatowski marked this conversation as resolved.
Show resolved Hide resolved

def order_by_id_query(relation)
"#{relation.table_name}.#{foreign_key(relation)} #{direction}"
end

def order_by_attribute_query
"#{attribute.tableize}.#{field} #{direction}"
end

def has_many_attribute?(relation)
Expand Down
2 changes: 1 addition & 1 deletion spec/example_app/app/dashboards/order_dashboard.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class OrderDashboard < Administrate::BaseDashboard
address_city: Field::String,
address_state: Field::String,
address_zip: Field::String,
customer: Field::BelongsTo,
customer: Field::BelongsTo.with_options(order: "name"),
patrickgramatowski marked this conversation as resolved.
Show resolved Hide resolved
line_items: Field::HasMany,
total_price: Field::Number.with_options(prefix: "$", decimals: 2),
shipped_at: Field::DateTime,
Expand Down
14 changes: 14 additions & 0 deletions spec/features/orders_index_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,18 @@
"Cannot delete record because dependent payments exist", type: :error
)
end

scenario "user sorts by belongs_to field" do
create(:order, customer: create(:customer, name: "Alpha"))
create(:order, customer: create(:customer, name: "Charlie"))
create(:order, customer: create(:customer, name: "Bravo"))

visit admin_orders_path

click_on "Customer"
expect(page).to have_content(/Alpha.*Bravo.*Charlie/)

click_on "Customer"
expect(page).to have_content(/Charlie.*Bravo.*Alpha/)
end
end
78 changes: 76 additions & 2 deletions spec/lib/administrate/order_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@

context "when relation has belongs_to association" do
it "orders by id" do
order = Administrate::Order.new(:name)
order = Administrate::Order.new
relation = relation_with_association(
:belongs_to,
foreign_key: "some_foreign_key",
Expand All @@ -95,9 +95,82 @@

ordered = order.apply(relation)

expect(relation).to have_received(:reorder).with("some_foreign_key asc")
expect(relation).to have_received(:reorder).with(
"table_name.some_foreign_key asc",
)
expect(ordered).to eq(relation)
end

context "when `order` argument valid" do
it "orders by the column" do
order = Administrate::Order.new(
double(to_sym: :user, tableize: "users"),
nil,
"name",
)
relation = relation_with_association(
:belongs_to,
klass: double(
table_name: "users",
columns_hash: { "name" => :value },
),
)
allow(relation).to receive(:joins).and_return(relation)
allow(relation).to receive(:reorder).and_return(relation)

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

context "when `order` argument invalid" do
it "orders by id" do
order = Administrate::Order.new(
double(table_name: "users", to_sym: :user),
nil,
"invalid_column_name",
)
relation = relation_with_association(
:belongs_to,
klass: double(
table_name: "users",
columns_hash: { name: :value },
),
)
allow(relation).to receive(:joins).and_return(relation)
allow(relation).to receive(:reorder).and_return(relation)

ordered = order.apply(relation)

expect(relation).to have_received(:reorder).with(
"table_name.belongs_to_id asc",
)
expect(ordered).to eq(relation)
end
end
end
end

describe "#column_exist?" do
context "when the table has the column defined" do
let(:table) { double(columns_hash: { "name" => :value }) }
let(:column) { :name }

it "returns true" do
expect(described_class.new.column_exist?(table, column)).to eql(true)
end
end

context "when the table has not the column defined" do
let(:table) { double(columns_hash: { "name" => :value }) }
let(:column) { :invalid_column_name }

it "returns false" do
expect(described_class.new.column_exist?(table, column)).to eql(false)
end
end
end

Expand Down Expand Up @@ -207,6 +280,7 @@ def relation_with_association(
klass: klass,
),
),
table_name: "table_name",
)
end
end