Ruby on Rails
SortHelper2 (Version #137)

by Stuart Rackham
Download
Screenshot

Helpers to sort tables using clickable column headers.

  • Consecutive clicks toggle the column’s sort order.
  • Sort state is maintained by a session hash entry.
  • Icon image identifies sort column and state.
  • Typically used in conjunction with the Pagination module.

NOTE: Requires Rails 0.11.0

Its use is straight-forward:

Download to app/helpers.

Controller:

   helper :sort
   include SortHelper

   def list
     sort_init 'last_name'
     sort_update
     @items = Contact.find(:all, :order => sort_clause)
   end

View (table header in list.rhtml):

   <thead>
     <tr>
       <%= sort_header_tag('id', :title => 'Sort by contact ID') %>
       <%= sort_header_tag('last_name', :text => 'Name') %>
       <%= sort_header_tag('phone') %>
       <%= sort_header_tag('address', :width => 200) %>
     </tr>
   </thead>

category:Helper



I put this:
  map.connect ':controller/:action/:sort_key/:sort_order'

in config/routes.rb
to get cleaner URL’s. Worked for me, YMMV

Also, the heading links drop pagination, if any.



To use with pagination:

def list
    sort_init 'last_name'
    sort_update
    @contact_pages, @contacts = paginate(:contacts, :order => sort_clause,:per_page => 10)
  end

I have modified this helper to allow sorting on associated models with one-to-many relationships.
It can be downloaded here and quick description of how to use it can be found on my blog here

- Jonathan Conway


Case Insensitive Sorting

To get case insensitive string sorting ( which is the default on MySQL but not SQLite and possibly other databases ) edit the following methods.

This code is for the associated model sorting version but could be adapted for the original by removing the @session@sort_name from the sort clause.


  def sort_clause()

      check_association_not_null 

      class_name = @session[@sort_name][:association].classify   
      myClass = Object.const_get( class_name )
      column_hash = myClass.columns_hash
      column = column_hash[ @session[@sort_name][:key] ]

      if column.type == :string      
        'lower(' + @session[@sort_name][:association] + '.' + @session[@sort_name][:key] + ') ' + @session[@sort_name][:order]      
      else      
        @session[@sort_name][:association] + '.' + @session[@sort_name][:key] + ' ' + @session[@sort_name][:order]        
      end
  end   

I also removed the is_association flag from the init method as it was unnecessary


  def sort_init( default_key, default_order = 'asc', name = nil, default_tablename = nil )
    @sort_name = name || params[:controller] + '_sort'
    @sort_default = {:key => default_key, :order => default_order, :association => default_tablename}
  end

I have modified this to work with sorting on multiple tables .
-George


WORD OF WARNING: This stores your current sort order in a session variable, so if you incorrectly initialize the sort to a bad column, you will get a continued SQL error until you reset the sort order or clear out your session. The session will not update if you change the sort_init default sort column. This was causing headaches for a coworker of mine and originally cost me about a half hour of development time. Doh!
- Rick Branson

by Stuart Rackham
Download
Screenshot

Helpers to sort tables using clickable column headers.

  • Consecutive clicks toggle the column’s sort order.
  • Sort state is maintained by a session hash entry.
  • Icon image identifies sort column and state.
  • Typically used in conjunction with the Pagination module.

NOTE: Requires Rails 0.11.0

Its use is straight-forward:

Download to app/helpers.

Controller:

   helper :sort
   include SortHelper

   def list
     sort_init 'last_name'
     sort_update
     @items = Contact.find(:all, :order => sort_clause)
   end

View (table header in list.rhtml):

   <thead>
     <tr>
       <%= sort_header_tag('id', :title => 'Sort by contact ID') %>
       <%= sort_header_tag('last_name', :text => 'Name') %>
       <%= sort_header_tag('phone') %>
       <%= sort_header_tag('address', :width => 200) %>
     </tr>
   </thead>

category:Helper



I put this:
  map.connect ':controller/:action/:sort_key/:sort_order'

in config/routes.rb
to get cleaner URL’s. Worked for me, YMMV

Also, the heading links drop pagination, if any.



To use with pagination:

def list
    sort_init 'last_name'
    sort_update
    @contact_pages, @contacts = paginate(:contacts, :order => sort_clause,:per_page => 10)
  end

I have modified this helper to allow sorting on associated models with one-to-many relationships.
It can be downloaded here and quick description of how to use it can be found on my blog here

- Jonathan Conway


Case Insensitive Sorting

To get case insensitive string sorting ( which is the default on MySQL but not SQLite and possibly other databases ) edit the following methods.

This code is for the associated model sorting version but could be adapted for the original by removing the @session@sort_name from the sort clause.


  def sort_clause()

      check_association_not_null 

      class_name = @session[@sort_name][:association].classify   
      myClass = Object.const_get( class_name )
      column_hash = myClass.columns_hash
      column = column_hash[ @session[@sort_name][:key] ]

      if column.type == :string      
        'lower(' + @session[@sort_name][:association] + '.' + @session[@sort_name][:key] + ') ' + @session[@sort_name][:order]      
      else      
        @session[@sort_name][:association] + '.' + @session[@sort_name][:key] + ' ' + @session[@sort_name][:order]        
      end
  end   

I also removed the is_association flag from the init method as it was unnecessary


  def sort_init( default_key, default_order = 'asc', name = nil, default_tablename = nil )
    @sort_name = name || params[:controller] + '_sort'
    @sort_default = {:key => default_key, :order => default_order, :association => default_tablename}
  end

I have modified this to work with sorting on multiple tables .
-George


WORD OF WARNING: This stores your current sort order in a session variable, so if you incorrectly initialize the sort to a bad column, you will get a continued SQL error until you reset the sort order or clear out your session. The session will not update if you change the sort_init default sort column. This was causing headaches for a coworker of mine and originally cost me about a half hour of development time. Doh!
- Rick Branson