administrate
administrate copied to clipboard
How to sort by relationship field
Hi all!
I searched through documentation and code and didn't find a way to sort the records by a relation field.
This is related to #265.
There is someone working on it? If not, I'd be happy to provide PR.
Hey, @Rodrigora! Thanks for the suggestion!
Right now this isn't supported. I'm a bit curious about how you'd sort by a relationship - it seems like it would vary depending on whether the relation is a has_many
, belongs_to
, has_one
, or polymorphic
relationship.
Can you elaborate on what behavior you'd like to see?
My models are:
class Product
belongs_to :category
end
class Category
has_many :product
end
I'd like to sort products by category name, since my products page has the columns id and category (Category column displays the category name).
I've used this before with spree: https://github.com/activerecord-hackery/ransack
Could be an easy win.
I've just implemented a very hacky version. This class sits at the bottom of the user controller. I'm not suggesting it as a fix but might help in your case :)
class SearchUser
def initialize(resolver, term)
@resolver = resolver
@term = term
end
SEARCH_TABLES = %w(addresses vouchers)
# Manually add the joins for these tables
def run
if @term.blank?
resource_class.all
else
resource_class.uniq
.joins(:addresses, user_vouchers: [:voucher])
.where(query, *search_terms)
end
end
private
delegate to: :resolver
def query
prefixed_attributes.map { |attr| "lower(#{attr}) LIKE ?" }.join(' OR ')
end
def search_terms
["%#{term.downcase}%"] * prefixed_attributes.count
end
def prefixed_attributes
[resource_class] + SEARCH_TABLES.flat_map do |table|
attributes_for(table).map { |attr| "#{table}.#{attr}" }
end
end
def attributes_for(dashboard)
Object.const_get(dashboard.classify + 'Dashboard')::ATTRIBUTE_TYPES.select do |_, type|
type.searchable?
end.keys
end
attr_reader :resolver, :term
end
Does anyone have any updates on this type of thing? Being able to sort/search by an attribute on a belongs_to association would be a huge win for me.
@nickcharlton We should look into this one for an upcoming release. There's a proposed solution in #750
I've been experimenting with this during this last couple of days. Here's what I have so far: https://github.com/thoughtbot/administrate/pull/1506
Just wanted to echo my support for a feature like this. Thank you!
We implemented sorting by relationship field by something like this.
class Comment
has_one :moderation
delegate :state, to: :moderation, prefix: true
end
class Moderation
belongs_to :comment
enum :approved, :disapproved
end
# comments_controller.rb
def scoped_resource
if order.order_by?(:moderation_state)
Comment.joins(:operation).merge(Moderation.order(state: order.direction))
else
Comment.default_scoped
end
end
I agree with @shouichi that overriding the controller is the best way forward at the moment. I think I would override order
instead. See this example, adapted from the example app:
module Admin
class ProductsController < Admin::ApplicationController
class OrderByProductMetaTag < Administrate::Order
def initialize(direction = nil)
super("product_meta_tag", direction)
end
def apply(relation)
relation.joins(:product_meta_tag).order("product_meta_tags.meta_title" => (direction || "asc").to_sym)
end
def ordered_by?(attr)
attr.to_s == "product_meta_tag"
end
end
def order
if sorting_attribute == "product_meta_tag"
OrderByProductMetaTag.new(sorting_direction)
else
super
end
end
end
end
The short-term task then is to document this.