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:

  1. 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.
  2. The sorting logic is not duplicated across controllers, and controllers don't have to define helper methods.
  3. It makes it easier for multiple tables on a page to have sortable columns.

Installing

gem 'sortable-table', github: 'caselle/sortable-table'

Configuration

Using sortable table involves the following steps:

  1. Define which columns in your table can be sorted, and how they are sorted.
  2. Using the parameters passed into your controller action, get the current sort column.
  3. Use the current sort column to order your data.
  4. Use the sort_by helper, to add links to the table header row which allow the table to be re-sorted by those columns.

Controller

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.

View

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.

Sorting Multiple Tables

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

Sort Column Definitions

There are two types of sort column definitions: SortColumnDefinition and SortColumnCustomDefinition.

Sort Column Definition

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.

Sort Column Custom Definition

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')

Sort Table

A SortTable is used to create the current sort column based on the params passed to the controller action.

Creation

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)

Current Sort Column

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.

Sort Column

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.

License

sortable-table is available under the MIT license. See the LICENSE file for more info.