The sorting of content tables by user input is a common scenario for web applications. Many solutions enable custom sorting, but they all imply huge complexity compared to the required functionality. They may be needed for more complex scenarios but the simple enhancement of custom sorting can be implemented without such overhead.

A simple solution enables easy maintenance and understanding. Consequently, the proposed solution is faster to develop and provides the same functionality. It is also compliant with ROCA meaning that JavaScript is only used for progressive enhancement but the page can be used without it.

The implementation changes are rather small. First, an intuitive graphical visualization of the order request like up and down arrows must be added. Next, a link with a parameter for sorting and a value for the corresponding name of the column to be sorted and the sort direction must be attached to the arrows. Be aware to URL-encode your sort string to prevent problems! The following code snippet visualizes the resulting HTML. The parameter is sort and the sortable column is named value. The ordering is represented by ASC and DESC.

<th>
  First Name
  <a href="/user.html?sort=value+ASC"></a>
  <a href="/user.html?sort=value+DESC"></a>
</th>

Additionally, logic to process the user’s ordering input must be implemented. It checks if the user requested a custom ordering and only applies valid order statements as will be explained after this code snippet.

@user = User.all

if params[:sort]
  order_params = sanitize_order params[:sort]

  @user = @user.order(order_params)
end

Validity checks of order statements also need to address and prevent possible SQL injections, ensured by checking each order parameter. Moreover, information displayed can be either stored in another table or does not exist in a single column, so that it needs to be enhanced through e.g. order_params.gsub('value', 'labels.value'). The following code snipped visualizes such cases. Multiple order statements can be connected with commas and need to be checked separately. Each statement then needs to be composed of two parts to be valid: The first states the name of the column and the second the order. Lastly, it is ensured that the table column to be sorted exists and the valid statements are rejoined.

def sanitize_order search_params
  param_array = search_params.split(',').compact.select do |order_column|
    column_and_order = order_column.split(' ')
    column_and_order.count == 2 &&
     ['firstname', 'lastname'].include?(column_and_order[COLUMN]) &&
     ['ASC', 'DESC'].include?(column_and_order[ORDER])
  end
  param_array.join(',')
end

In conclusion, the presented solution avoids the complexity of a big JavaScript library and still enables sorting for users while also being compliant with ROCA. It does not feel like a magic black box and the simplicity of the solution makes it easy to understand and change. Moreover, it does not rely on an external library and therefore avoids any required updates and possible compatibility problems. Lastly, it is easy to integrate with other libraries like pagination since data retrieval does not change.