Sorting tables by columns

What I’m trying to do is have clickable column headers that will sort
the table by that column. What I have below works, except there is only
one variable storing the sort direction for all the columns, whereas I
need a separate one for each column name.

list view:

<%= link_to 'Category', :action => 'list', :order => 'categories.category' %> <%= link_to 'Amount', :action => 'list', :order => 'amount' %> <%= link_to 'Date', :action => 'list', :order => 'date' %> <%= link_to 'Location', :action => 'list', :order => 'location' %> <%= link_to 'Note', :action => 'list', :order => 'note' %>

list:

order = @params[:order] ||= ‘date’

unless session[:dir]
session[:dir] = ’ asc’
end

session[:dir] = (session[:dir] == ’ desc’) ? ’ asc’ : ’ desc’

@all = Activity.find(:all, :order => order + session[:dir], :include =>
:category)

I’d like the session hash to be something like:

session = {
:dir => {:date => ’ asc’, :location => ’ desc’, :amount => ’ desc’}
#etc
}

I need to do something like session[:dir][order] but I don’t know the
proper syntax. Ideas?

Thanks,
Chris

On 1/8/06, Chris S. [email protected] wrote:

What I’m trying to do is have clickable column headers that will sort
the table by that column.

Do you have an aversion to doing this with Javascript? See
sorttable: Make all your tables sortable for an example.

If you want to do it on the server:

@all = Activity.find(:all, :order => “#{@order}
#{session[:dir][@order.to_sym]}”, :include =>
:category)

Chris,

I’ve been patching something like this together recently for my own app.
I can describe it briefly for you.

== Templates ==

In the templates I put a link much like yours into the table header. In
my case I created a helper function that generates the link based on the
column name. The helper also applies a CSS class of “sorted” to the
link if the sorted column is the current one.

the helper looks something like this

== application_helper file or controller_helper

def sorted_column(name,ukey = nil)
key = ukey || name #allows the passed parameter name to be set
#otherwise it uses the column name
link_to “#{name}”, :sort=>key,
{“class”=>(key == @sort)?“sorted”:“unsorted”}
end

== Controller ==

def list
@sort = params[:sort] || session[:sort] || “default”
session[:sort] = @sort
@person_pages, @people = paginate :people, :order => sorted_by(@sort)
end

def sorted_by(key)

This is important because it prevents SQL injection and provides

default

behavior if naughty users change the URL. It also keeps the URLS

clean.
case key
when “lastname” : “lastname, firstname”
else “firstname, lastname”
end
end

It isn’t too difficult to set this up in your application controller
with some default settings to give all controllers this action.

** reasons not to use javascript.
If you have a lot of records, you would need to pull them all and send
them to the client to get it to properly sort. Otherwise you would only
be sorting the 10 records it pulled the first time.

I’m typing this from memory, so expect bugs.

This whole thing could be AJAX’d too, but I haven’t gotten to that yet.