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

Default order/sort of lists #442

Closed
gylaz opened this issue Jan 29, 2016 · 32 comments
Closed

Default order/sort of lists #442

gylaz opened this issue Jan 29, 2016 · 32 comments

Comments

@gylaz
Copy link

gylaz commented Jan 29, 2016

It would be nice if there was an option to configure the default order that record collection uses when displaying a list on the dashboard.

Something like:

class UserDashboard < Administrate::BaseDashboard
  ...
  def default_order
    resources.order(name: :desc)
  end
end
@FelipePLima
Copy link

@gylaz The user would choose the attribute used in default_order method ?

@avk
Copy link

avk commented Sep 17, 2016

Is there a way to change the default order now, for all dashboard/models by default?

@ianagne
Copy link
Contributor

ianagne commented Sep 26, 2016

@avk As long as you're ok with overwriting a private method, you can definitely set a default order. You'll just have to check the source every update to make sure the private API you're using doesn't change.

For example, say you have a User model with email attribute. If you want to sort by email ascending by default, you could add the following to app/controllers/admin/users_controller.rb:

module Admin
  class UsersController < Admin::ApplicationController
    private

    def order
      if params[:order] && params[:direction]
        @_order ||= Administrate::Order.new(params[:order], params[:direction)
      else
        @_order ||= Administrate::Order.new(email: :asc)
      end
    end
  end
end

@avk
Copy link

avk commented Sep 26, 2016

I found another way that worked for me, across all dashboards:

module Admin
  class ApplicationController < Administrate::ApplicationController
    before_filter :default_params

    def default_params
      params[:order] ||= "created_at"
      params[:direction] ||= "desc"
    end
  end
end

@ianagne
Copy link
Contributor

ianagne commented Sep 26, 2016

👍 That is a way better way to set a default order.

@allthesignals
Copy link

I'm using a gem that handles ordering through a method #roots_and_descendants_preordered (specifically, the closure_tree gem, which has preordering ClosureTree/closure_tree#38). Setting this as the default scope seemed to throw a SQL error from collection_presenter.attributes_for(resource).

default_scope -> { roots_and_descendants_preordered }

I wondered if there were a way to set a default order in administrate by calling a class method. Any thoughts? Thank you!

@danielricecodes
Copy link

very nice @avk.

It would be nice to be able to sort nulls also. I tried "DESC NULLS LAST" which is fine in Postgres but I got an error from Administrate.

Direction "DESC NULLS LAST" is invalid. Valid directions are: [:asc, :desc, :ASC, :DESC, "asc", "desc", "ASC", "DESC"]

Fair enough Administrate.

@rozhok
Copy link
Contributor

rozhok commented Jul 17, 2017

In rails 5.1 I've had to change before_filter into before_action:

module Admin
  class ApplicationController < Administrate::ApplicationController
    before_action :default_params

    def default_params
      params[:order] ||= 'id'
      params[:direction] ||= 'desc'
    end
  end
end

@nickcharlton
Copy link
Member

I’m going to close this as that seems like a good solution. If you’re not on Rails 5.1 yet, I’d recommend standardising on before_action, like @rozhok suggests. Thanks!

jessieay added a commit to codeforamerica/michigan-benefits that referenced this issue Sep 12, 2017
* Default sort order to show most recently created first
* Show office location on the dashboard
* Ref for order code: thoughtbot/administrate#442 (comment)
jessieay added a commit to codeforamerica/michigan-benefits that referenced this issue Sep 12, 2017
* Default sort order to show most recently created first
* Show office location on the dashboard
* Ref for order code: thoughtbot/administrate#442 (comment)
alexsoble added a commit to studentinsights/studentinsights that referenced this issue Oct 25, 2017
alexsoble added a commit to studentinsights/studentinsights that referenced this issue Oct 27, 2017
alexsoble added a commit to studentinsights/studentinsights that referenced this issue Oct 27, 2017
@giuseb
Copy link

giuseb commented Nov 15, 2018

I am building a Rails 5.2.1 app with Administrate 0.11.0.
I tried @rozhok's solution to enforce a default sorting order in a dashboard index of a Recording model, like so:

before_action :default_params

def default_params
  params[:order] ||= 'start'
  params[:direction] ||= 'desc'
end

but the server log says:

Unpermitted parameter: :recording
  Rendering admin/recordings/index.html.haml within layouts/admin/application
Unpermitted parameters: :order, :direction
Unpermitted parameters: :order, :direction
Unpermitted parameters: :order, :direction
Unpermitted parameters: :order, :direction

...and the desired sorting on the start field does not work.
I don't know if it's relevant, but when I click on the Start header in order to manually sort records (which indeed works), the URL becomes:

http://localhost:3000/admin/recordings?recording%5Bdirection%5D=asc&recording%5Border%5D=start

I am afraid I am missing something obvious, but I am thoroughly stumped...

@hartsick
Copy link

hartsick commented Nov 15, 2018

@giuseb I also just ran into this, and can confirm the behavior changed between 0.10.0 and 0.11.0.

This piece in code expects a different nesting of params than before:
app/controllers/administrate/application_controller.rb in 0.11.0:

    def order
      @order ||= Administrate::Order.new(
        params.fetch(resource_name, {}).fetch(:order, nil),
        params.fetch(resource_name, {}).fetch(:direction, nil),
      )
    end

(expects order & direction to be under key resource_name)

vs.

app/controllers/administrate/application_controller.rb in 0.10.0:

    def order
      @order ||= Administrate::Order.new(params[:order], params[:direction])
    end

(expects order & direction to be at root of params)

Here's what I did for now... mostly a workaround for not being able to do a deep_merge on params:

def default_params
  resource_params = params.fetch(resource_name, {})
  order = resource_params.fetch(:order, "created_at")
  direction = resource_params.fetch(:direction, "desc")
  params[resource_name] = resource_params.merge(order: order, direction: direction)
end

nomadicoder added a commit to tulibraries/manifold that referenced this issue Dec 6, 2018
- Cannot update events when we set sort ordering on start date when we
  pass the :order and :direction parameters.
- Reference
  [thoughtbot/administrate#442 (comment)]
cdoyle-temple pushed a commit to tulibraries/manifold that referenced this issue Dec 7, 2018
- Cannot update events when we set sort ordering on start date when we
  pass the :order and :direction parameters.
- Reference
  [thoughtbot/administrate#442 (comment)]
@phoet
Copy link

phoet commented May 2, 2019

this is a much simpler workaround (copy past from the applicationcontroller). wouldnt it be a nobrainer to add configuration-options to set those defaults?

    def order
      @order ||= Administrate::Order.new(
        params.fetch(resource_name, {}).fetch(:order, 'created_at'),
        params.fetch(resource_name, {}).fetch(:direction, 'desc'),
      )
    end

@richardonrails
Copy link

+1 for adding a default of created_at (descending) to all dashboards. Thanks @phoet for the snippet.

@philliplongman
Copy link

If this is the solution you're going with, it should be added to the comments in the controllers. That's the second place I looked for a method I needed to overwrite (after the dashboard).

@pablobm
Copy link
Collaborator

pablobm commented Dec 12, 2019

Hello all. Thank you for the discussion and the alternatives proposed. I'd be happy to accept a PR that introduced methods sorting_attribute and sorting_direction (or something similar), in Administrate::ApplicationController. It should include tests and documentation.

@ksearfos
Copy link

ksearfos commented Mar 4, 2020

Tests and documentation are very important. I can't figure out how to use this. AT ALL.

@atinder
Copy link

atinder commented May 3, 2020

Not working for Rails 6 :\

@sedubois
Copy link
Contributor

sedubois commented May 3, 2020

@atinder I use the code below in my Rails 6.0.2.2 app, no problem with Rails 6.

# app/controllers/admin/application_controller.rb
module Admin
  class ApplicationController < Administrate::ApplicationController
    ....

    def order
      @order ||= Administrate::Order.new(
        params.fetch(resource_name, {}).fetch(:order, default_sort[:order]),
        params.fetch(resource_name, {}).fetch(:direction, default_sort[:direction]),
      )
    end

    # override this in specific controllers as needed
    def default_sort
      { order: :updated_at, direction: :desc }
    end
    
    ...
  end
end

@atinder
Copy link

atinder commented May 3, 2020

thanks a lot @sedubois

@nickcharlton
Copy link
Member

@sedubois, can we improve our docs around this? Seems like it's still a bit confusing

@sedubois
Copy link
Contributor

sedubois commented May 4, 2020

Yes @nickcharlton that would be helpful. I can just paste that snippet somewhere why not. Where should it fit in the docs?

@nickcharlton
Copy link
Member

"Customising Dashboards", perhaps? It seems like the closest place with the current arrangement.

@valcaro87
Copy link

is there a way to order two data by 'last_name' and 'id' at the same time?
like example>

def order
@order ||= Administrate::Order.new(
params.fetch(resource_name, {}).fetch(:order, ['last_name'.'id']),
params.fetch(resource_name, {}).fetch(:direction, 'asc')
)
end

@atinder
Copy link

atinder commented Apr 6, 2021

found a better way in documentation

    def default_sorting_attribute
      :id
    end

    def default_sorting_direction
      :desc
    end

@kaka-ruto
Copy link

Thanks @atinder. Works for me on Rails 6

@valcaro87
Copy link

is there a way we can sort by two columns? example i have 2 columns, by "last_name" and "amount"?

@kaka-ruto
Copy link

@valcaro87 the sorting example shared by @atinder above is for all tables, where it makes sense to sort by universal items such as id or created_at columns.

Did you want to sort a single table or all your tables have the last_name and amount columns?

@valcaro87
Copy link

valcaro87 commented Apr 16, 2021

@kaka-ruto single table.. i have "sales" table. i want to sort by "last_name" and their "amount" in desc order..
for example, in my table, 2 employees having the same family name.. so the order should be:

  1. Jones - $5
  2. Smith - $17
  3. Smith - $8
  4. William - $23

( we can achieved this in sql by: SELECT * FROM sales ORDER BY last_name DESC, amount DESC; )

@kaka-ruto
Copy link

kaka-ruto commented Apr 16, 2021

Done a little digging and it seems at the moment you can only sort by a single column at a time @valcaro87 -> codebase

@kaka-ruto
Copy link

Something close that could help is to use collection filters

@pablobm
Copy link
Collaborator

pablobm commented Apr 22, 2021

If you are not looking for much flexibility, it might be possible to sort by multiple fields. Let me explain.

It's possible to define a default sorting to be as complex as you want. This is an example based on Administrate's own example app. It overrides CustomersController#scoped_resource to define a default ordering for customers:

class Admin::CustomersController < Admin::ApplicationController
  private

  def scoped_resource
    Customer.where(hidden: false).order(:country_code, :name)
  end
end

If default ordering is all you need, that's your solution.

If instead you are looking for a lot of flexibility, that's probably not supported at the moment. For example, say that you are in the same customers index and you want the users to be able to click on "Email", then "Territory", and have all the "Australia" records coming first, ordered by email.

Not only this is not possible at the moment, but also it would be complex to implement. We would need to make the links in the table headers "remember" what the previous clicked columns were. So for example, if you click "Email" and then "Territory", the URI would look something like /admin/customers?customer[direction]=asc,asc&customer[order]=territory,email. That way Administrate would know which columns are involved in the sorting, and in which order.

There's an intermediate way though...

You could override the index template to provide your own links to "blessed" orders, or in general scopes of any type that you need.

For example, I tried by adding this link to the index template of the example app:

 </header>
 
 <section class="main-content__body main-content__body--flush">
+  <p><%= link_to "Special order", request.path + "?special-order" %></p>
+
   <%= render(
     "collection",
     collection_presenter: page,

Then I can read this special-order query param from scoped_resource and implement any order that I wish:

class Admin::CustomersController < Admin::ApplicationController
  private

  def scoped_resource
    if @special_order
      Customer.where(hidden: false).order(:country_code, :name)
    else
      Customer.where(hidden: false)
    end
  end
end

I call it @special_order instead of params["special-order"] because I need one little hack to avoid an ActionController::UnpermittedParameters error. I do this by adding the following to Admin::ApplicationController:

  before_action :read_special_order

  def read_special_order
    @special_order = params.key?("special-order")
    params.delete("special-order")
  end

This registers the presence of the query param in the instance variable, then deletes the param so that it doesn't cause an error later on.

@joel-vl
Copy link

joel-vl commented Mar 30, 2024

The solution by atinder works. Overwrite default_sorting_attribute or default_sorting_direction in your dashboard controller like this:

def default_sorting_attribute
  :created_at
end

def default_sorting_direction
  :desc
end

The documentation for this solution can be found here: https://administrate-demo.herokuapp.com/customizing_controller_actions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests