Sortable Table by Caselle
The sortable-table gem allows you to sort table columns similar to RailsCasts #228 Sortable Table Columns.
Rather than adding helper methods to a controller, sortable-table creates a sort column object. This approach provides the following benefits:
- More complex sort criteria can be defined for a column. The RailsCasts approach only allows a single column to be sorted. This approach allows additional columns to be involved in the column sort.
- The sorting logic is not duplicated across controllers, and controllers don't have to define helper methods.
- It makes it easier for multiple tables on a page to have sortable columns.
gem 'sortable-table', github: 'caselle/sortable-table'
Using sortable table involves the following steps:
- Define which columns in your table can be sorted, and how they are sorted.
- Using the parameters passed into your controller action, get the current sort column.
- Use the current sort column to order your data.
- Use the
sort_by
helper, to add links to the table header row which allow the table to be re-sorted by those columns.
Create sort column definitions which define how each column can be sorted. Create a sort table that holds those sort column definitions as well as optional default sort column information. Then use the sort table to get the current sort column.
def sort_column
date_sort = SortableTable::SortColumnCustomDefinition.new('date',
asc: 'date asc, number asc',
desc: 'date desc, number desc')
number_sort = SortableTable::SortColumnDefinition.new('number')
sort_table = SortableTable::SortTable.new([date_sort, number_sort])
sort_table.sort_column(params[:sort], params[:direction])
end
Use the current sort column to order the records you pass to the view.
def index
@sort_column = sort_column
@items = Model.order(@sort_column.order)
end
Make the sort column available to the view, it will be used by the sort_by
helper.
Use the sort_by
helper to add links to columns which you want to sort.
%table
%tbody
%tr
%th= sort_by 'number', title: 'Number', current_column: @sort_column
%th= sort_by 'date', title: 'Date', current_column: @sort_column
%th Description
%tbody
= render @items
If the column passed to the sort_by
is the current sort column, the sort link it creates will switch the direction that the column is sorted by.
If you have multipe tables to sort on a view, then you'll need to add a prefix to the sorting params for each table. E.g., if you have a foo table and a bar table, instead of just having :sort and :direction params, you would want :foo_sort
, :foo_direction
, :bar_sort
, and :bar_direction
params. In other words, you'll want a table-specific prefix for each param.
To add a table-specific prefix, do the following:
Assign a sort column for each table. Use the param prefix when generating the sort column.
sort_table.sort_column(params[:foo_sort], params[:foo_direction])
Pass :prefix
to the sort_by helper
.
%th= sort_by 'name', title: 'Name', prefix: 'foo_', current_column: @foo_sort_column
There are two types of sort column definitions: SortColumnDefinition
and SortColumnCustomDefinition
.
SortColumnDefinition
simply allows you to pass the column used to sort. Depending on the sort direction the order will simply be "<column> asc" or "<column> desc".
The column should be have the same casing as the database. E.g., if the column is "Timmy", create SortableTable::SortColumnDefinition.new('Timmy')
not SortableTable::SortColumnDefinition.new('timmy')
.
The column name is the key used by the SortTable.
SortColumnCustomDefinition
allows you to specify any custom order for ascending and descending directions. The first parameter passed when creating a SortColumnCustomDefinition
is the "key" used by the SortTable.
date_sort = SortableTable::SortColumnCustomDefinition.new('date',
asc: 'date asc, number asc',
desc: 'date desc, number desc')
A SortTable
is used to create the current sort column based on the params passed to the controller action.
To create a SortTable
, pass in the sort column definitions for the table.
Additional options that can be passed as well are:
default_column
: The column to use for sorting if no sort column param is passed to the controller action. If this option is not passed, the first sort column definition is used. The value for this is the "key" of a sort column definition.default_direction
: The direction to use for sorting the default column if no sort direction param is passed to the controller action. If this option is not passed, :asc is used. :asc or :desc
In the following example, date and number sort column definitions are created. If no sort params are passed to the controller action, the current sort column will be ordered by date ascending.
date_sort = SortableTable::SortColumnDefinition.new('date')
number_sort = SortableTable::SortColumnDefinition.new('number')
sort_table = SortableTable::SortTable.new([date_sort, number_sort])
In this example, date and number sort column definitions are created, and the default order will be number descending.
date_sort = SortableTable::SortColumnDefinition.new('date')
number_sort = SortableTable::SortColumnDefinition.new('number')
sort_table = SortableTable::SortTable.new([date_sort, number_sort],
default_column: 'number', default_direction: :desc)
Call the sort_column
SortTable method to get the current sort column.
sort_table.sort_column(params[:sort], params[:direction])
If params[:sort]
is missing, the sort table default column will be used. If params[:sort]
is not a recognized sort column definition key, the sort table default column will be used.
If params[:direction]
is missing, the sort table default direction will be used.
A SortColumn
represents the current sort column. It has the following attributes:
order
: The order that can be passed to an ActiveRecord order method.YourModel.order(sort_column.order)
column
: The sort column. Corresponds to a sort column definition key.direction
: The sort direction, 'asc' or 'desc'.
Generally, a user of SortColumn
will only use the order
attribute. The other attributes are used by helper methods.
sortable-table is available under the MIT license. See the LICENSE file for more info.