1. Skip to navigation
  2. Skip to content

The ELC Community Blog

A knowledge exchange on Ruby on Rails and Agile Development


sortable column headers

by cnady on May 08, 2007

ELC Plugins

I wanted the ability to sort my tabular data using column header links. I wanted the links for each column to toggle between ASC and DESC depending on the current sort direction for that column. I also wanted the system to remember the sort order of a given table even after I navigated away from and back to the page that contained it. My current solution is the sortable_column_headers plugin (SCH).

UPDATE: Some significant updates have been made to this plugin as of 2007 06 10. They include:

  • Sort solutions now span controllers.
  • Multiple sort solutions on a single page are more robust.
  • Can override ASC default with DESC.
  • Methods now take options as a Hash (backwards compatible!).
  • Demo app includes multiple sort solutions and session debug info.

UPDATE: Fixed bug regarding aliases and multiple sort solutions, 2007 06 18.

First, in my controller I tell SCH which fields I want sortable. In the following example, I tell SCH I need to establish a sorting solution called "listing" (to differentiate it from other sorting solutions which may exist on the same page). This solution will sort the "author_id" column in the Book model, and we want our link to be pretty, so please call it "author" (instead of "books.author_id", more on this later).

   1  add_to_sortable_columns('listing', 
   2    :model => Book, 
   3    :field => 'author_id', 
   4    :alias => 'author')

You don't need to specify an alias. Or you can omit the model and specify the field outright (:field => "books.author_id"). You have a lot of options detailed in the README. Also, a single sorting solution can have as many "add_to_sortable_columns" as you need for all the fields returned in your database query. You can bulk add all the fields in a single model like this:

   1  add_to_sortable_columns('listing', :model => Book)

Second, in my view I need to use the "sort_param" method to add the SCH parameter to my links.

   1  <%= link_to 'Author', sort_param('listing', :alias => 'author') %>

The call to "sort_param" in the previous example may produce a URL param like "?sortasc=listing-author". The sorting solution label is always appended to the name of the field, even if you have specified an alias.

Last, going back to my controller, I need to ask SCH for the sorting solution by using the "sortable_order" method. In the following example, I tell SCH I want the solution for "listing", and sort on "books.author_id DESC" by default if the user is viewing the data for the first time.

   1  @books = Book.find :all, 
   2    :order => sortable_order('listing', 
   3      :model => Book, 
   4      :field => 'author_id',
   5      :sort_direction => :desc)

The call to "sortable_order" in the previous example may produce something like "books.author_id DESC".

If you are interested in such things, SCH does some of its magic by storing previous sort orders for each sorting solution in "sessions[:sortable_column_headers]".

You can get it here: https://svn.elctech.com/svn/public/sortable_column_headers/

UPDATE: I put a very small demo Rails application using SCH called (not surprisingly) "sortable_column_headers" in our SVN repository. You can get it here: https://svn.elctech.com/svn/public/demo/sortable_column_headers/

See our other Rails Plugins

Comments

Ogre at 7:49 PM on May 23 2007

I’ve been trying to get this to work but have failed. It displays my columns nicely, but clicking on the column name changes nothing, it continues to sort only by the default column I specified with “sortable_order”, ignoring the sortasc=column parameter and never switching the link to “sortdesc=”. I’ve verified that the sql select statement is unchanged. Also, I checked the session file and it doesn’t have any obvious references to sorting stored in it.

cnady at 8:45 PM on May 26 2007

Hmmm … hard to help without looking at your code, so I’ve made a small demo Rails application which successfully uses SCH! Yay! I’ve posted a link to it in an update to the post above. I hope this helps. Cheers!

Sean Geoghegan at 4:52 AM on June 12 2007

I tried using this and found a bug that would cause the sort order to always be ‘ASC’. On line 187 you have this:

sch_key = self.sortable_column_header_data[sortable_key].blank? || ’’

This will cause sch_key to always be ’’ when there is a valid sort field specified. Then when you go onto compare sch_key with the current sort state you will never get a match since you are looking for ’ ASC’ or ’ DESC’ instead of ‘field ASC’ or field DESC’.

Changing that line to:

sch_key = self.sortable_column_header_data[sortable_key] || ’’

fixes the problem.

cnady at 8:31 PM on June 12 2007

Thanks Sean! Yeah, sloppy cut-n-paste on my part. I have updated SCH as of this comment. Cheers!

chase at 6:46 PM on June 15 2007

This plugin seems to be exactly what I was looking for, however, both /script/plugin and RaPT are having trouble installing from the URL above. Any thoughts?

cnady at 5:55 AM on June 16 2007

Hey Chase. Yeah, whoever is maintaining our SVN repository is trying to do something clever with HTTPS and it isn’t working 100% yet :) Try grabbing it directly from our repository into your Rails app with Subversion like this (you should execute this command from within your Rails app’s root directory): svn export https://svn.elctech.com/svn/public/sortable_column_headers ./vendor/plugins/sortable_column_headers

mathsfan at 1:55 PM on June 27 2007

Thanks cnady,I’ve download the subversion here http://subversion.tigris.org/files/documents/15/38369/svn-1.4.4-setup.exe,now i can use svn command:)

arash at 4:34 AM on June 28 2007

Will this plugin also let you sort on activerecord assocations?

Kinda like something at http://blog.vixiom.com/2006/09/27/ruby-on-rails-order-by-associated-model/

Thanks!

Mike at 2:44 PM on June 28 2007

hi there cnady, great work on this plugin. I’m a total noob to RoR, but I’m really enjoying learning it. I have the SCH working, with one small issue. My list view is using the paginate method. The sortable columns work perfectly, but the pagination has stopped working. I know I have to somehow reference the sortable columns in the ‘paginate’ line, but everything I’ve tried has failed miserably…Any ideas would be greatly appreciated…cheers!

Here’s the code in my controller:

   1  @user_report_pages, @user_reports = paginate :user_reports, :per_page => 10
   1  add_to_sortable_columns('sort_by_date', :field => 'user_reports.created_at', :sort_direction => :asc)
   1  @user_reports = UserReport.find :all, 
   2  :order => sortable_order('sort_by_date', 
   3  :field => 'user_reports.created_at', 
   4  :sort_direction => :desc)

nady at 4:56 PM on June 28 2007

Howdy arash! Yes, you can definitely sort on associations. An example of this exists in the plugin’s accompanying README file.

arash at 6:17 PM on June 28 2007

Thanks got it!

Any way to sort a ferret index return (using acts_as_ferret)?

cnady at 6:34 PM on June 28 2007

Hey Mike. Taking a quick look at your code, and without any testing, it looks to me like you could just take the :order clause from the UserReport.find in line three, add it to the paginate call in line one, and then get rid of line three entirely. Make sure you call add_to_sortable_columns before the paginate.

Mike at 11:34 AM on June 29 2007

That did it! Thanks cnady!

reddy at 11:13 AM on July 2 2007

Hi,

Can anybody explain me how to patch/install this plugin to the alreday existing application?

Thanks & Regards reddy g.p

cnady at 6:57 PM on July 2 2007

Howdy reddy! Please see my response to Chase on June 15.

gpreddy at 4:50 AM on July 3 2007

Hi cnady,

Is this plugin overwrites any existing files? If yes, let me know which files i need to take back up?

Thanks for help in advance

Thanks& Regards Purushotham Reddy G

cnady at 3:57 PM on July 5 2007

Gpreddy, if you follow the SVN checkout process described in the June 15 post I mentioned, the only files which should be overwritten are any pre-existing SCH plugin files. To be safe, please create a new Rails app for testing and then install SCH for it first to make sure it works for you.

Mike at 8:01 PM on July 6 2007

Hi Cnady, Thanks for all your help with this plugin.

I added a checkbox to toggle my list view between “All Reports” and “Open Reports”. I’m storing a value – 1 – in @openonly. If there is no value in @openonly, I’m displaying “All Reports”, if there is a value, I’m displaying “Open Reports”.

This works independently of the SCH. The problem is when I’m viewing “Open Reports Only”. When I then click on the SCH Links, its displaying all the reports. I think I know why this is happening, but I wanted to see if you had any ideas. Here’s my controller code:

   1  def list
   2    if !params[:lastname].blank?
   3        conditions = ["last_Name = ?", params[:lastname]]
   4    elsif !params[:state_id].blank?
   5        conditions = ["state_id = ?", params[:state_id]]
   6    else
   7        conditions = nil
   8    end
   9  end
   1  @open_only = params[:open_only]
   1  add_to_sortable_columns('sort_by_date', :field => 'user_reports.created_at', :sort_direction => :asc)
   1  if @open_only.blank?
   2      @user_report_pages, @user_reports = paginate :user_reports, :order => sortable_order('sort_by_date', :field => 'user_reports.created_at', :sort_direction => :desc), :per_page => 10   
   3  else
   4      @user_report_pages, @user_reports = paginate :user_reports, :conditions => {:report_status => "Open"}, :order => sortable_order('sort_by_date', :field => 'user_reports.created_at', :sort_direction => :desc), :per_page => 10   
   5  end

It seems like I need an alternate add_to_sortable_columns method if there is a value in @openonly…but I’m not sure how or if i’d be able to add a condition without digging into the plugin code. Sorry for the lengthy post.

- mike

Eric at 1:05 AM on July 7 2007

I notice that when clicking on a column, the ?sortasc/?sortdesc overwrites any parameters already in the URL. this is an issue for me because I need to query string to read something like ”/?sortasc=listing-artists.name&artistID=1”

can you point me to the right direction on how I can do this with your plugin?

Mike at 7:19 PM on July 7 2007

Hi Cnady, I’m using a checkbox to toggle my list view between displaying “all reports” and “open reports”. When my list view is displaying only open reports, clicking the sortable column link, always displays “all reports”.

Is there a way to add a condition to the: add_to_sortable_columns method? I could put wrap that in an if statement…any thoughts to making the sortable columns work with a checkbox, which applies a condition to the list view?

mathsfan at 4:17 PM on July 10 2007

Hi Cnady,I have a question to ask you,can i use SCH to list two or more tables?Today i try to use it,but have problem.I’m sorry so poor english```

cnady at 5:07 PM on July 10 2007

Howdy Eric! “sort_param” returns a hash which you can merge with whatever you want. For example: sort_param(...).merge({artistID=>1,artistName=>‘cnady’}) or sort_param(...).merge(params).

cnady at 5:22 PM on July 10 2007

Howdy Mike! Correct me if I’m wrong, but you are providing your users a checkbox to pass a param which modifies your query and you need to recycle that param? I think my response on July10 to Eric’s July06 post addresses that issue. Post again if it doesn’t! :)

cnady at 5:25 PM on July 10 2007

Howdy Mathsfan! You can use SCH on more than one table (sorting solution) and on more than one table on the same page. This demo application contains an example of this: https://svn.elctech.com/svn/public/demo/sortable_column_headers/

Mike at 9:09 PM on July 10 2007

Thank you Cnady! I’m still a totay nuby, but I am truly enjoying learning RoR. Thanks again for the site and the plugin! :) – Mike

mathsfan at 1:45 AM on July 11 2007

Thank you Cnady!Later i know the mistakes,i use the same name!!!I read your ROR application now,i have a new question to ask you,can i use SCH for search result data?I use it like this:

add_to_sortable_columns(‘product_list_s’,Product,’aid’,’商品编号’) @pages, @searchresult = paginate_collection Product.find(:all, :conditions=>[“aid like ?”,”#{@aid_search}“], #:order=>”aid desc”, :order => sortable_order(‘product_list_s’,Product,’aid’)), :limit=>”50”), :page => @params[:page] but have the error,i wanna know can the SCH support it?Thanks```

mathsfan at 2:29 AM on July 11 2007

To correct a mistake,”:order => sortable_order(‘product_list_s’,Product,’aid’)), ” has a spare “)”.But the paginate can’t well work now,when i link next page,it redirect the list page:( Can help me?I wanna hope you can understand my poor english.

mathsfan at 7:53 AM on July 11 2007

I really want to how can i use SCH to list search result.I think the SCH plugin can’t support this,right?Can you improve the SCH to support,thanks.

mathsfan at 12:31 PM on July 11 2007

To our friends’s help,i solve the problem.Thanks for your plugin.I really like it.

Kevin at 5:24 PM on July 27 2007

Hi Colman, thanks for the plug-in – it works great. I was wondering if you could offer me any feedback about the best way to include a :has_many relationship among the sortable columns. For instance, suppose I have a projects table, and each project :has_many employees assigned to the project, via a foreign key in the employees table. I would like to display a page in my app with each project name and the number of employees assigned to the project (project.employees.count), but I can’t seem to figure out how to make the count column sortable. I tried something like this:

add_to_sortable_columns(‘project’, :field => ‘employees.count’) <%= link_to “Project”, sort_param(‘project’, :field => ‘employees.count’) %>

But that causes a SQL error. I’ve been playing around with other options, but thought I would post it here, since there’s probably something pretty obvious that I’m simply overlooking.

Thanks!

cnady at 10:26 PM on July 28 2007

Howdy Kevin! Keep in mind all SCH really does is insert an ORDER BY clause into your db query. So if you know how to accomplish your goal in the context of a db query, then you might be able to shoehorn it into SCH. But I can’t think of how to do that off the top of my head. I suspect part of the solution has to do with the :select option of your AR model’s “find” method? Good luck! Post back here with a solution if you find one! Cheers!

nd at 9:01 PM on July 31 2007

Is there an easy way to find out which column is being sorted and in which directions. I want to put an up or down arrow next to the sorted column.

Thanks…

cnady at 1:40 AM on August 7 2007

Howdy nd! Whenever a user clicks on an SCH link, the field and sort direction is stored in “session[:sortable_column_headers]” for the appropriate sort solution with the most recent click inserted at element0.

LittleTrish at 2:32 PM on August 15 2007

This is great! Thanks for the plugin. However, I am a bit confused about the “Multiple sort solutions”. Does this mean that I have many columns that are able to sort, or that I can sort many columns at once (i.e. sort by Author and then by Book title). I am looking for the latter, but it appears this plugin does not have this capability. Am I missing something?

Thanks so much for your help! Trish

cnady at 6:04 AM on August 28 2007

Howdy LittleTrish! Sorry to take so long getting back to you. Been busy ;) “Multiple sort solutions” refers to how many sets of data you will be sorting on a given page. For instance, the SCH demo shows two sorting solutions.

Tom at 7:52 PM on September 9 2007

Great, great plugin, big thanx!

TC at 8:00 PM on September 18 2007

Hey cnady. Thanks for the plugin. Following up with nd’s question… Is looking at the string stored in the session value the best way to determine how to display an up/down arrow next to the sorted column? It looks like, in the view, we would need to parse the value of this string to determine (1) which column to show an arrow next to and (2) if it should be an up arrow or a down arrow. Is this true?

Steve F at 11:58 AM on October 5 2007

Hi,

has anybody managed to successfully integrate sort_column_header with the will_paginate plugin?

While I can get them to play nice, in the sense that there are no execution errors, clicking on a subsequent page (or the Next link) does not render the next set of results.

Steve F at 12:46 PM on October 5 2007

On a related comment, has anybody tried to use this plugin with data that’s not directly linked to a table? i.e. tabular data from an array?

MichaelB at 1:18 PM on October 8 2007

I haven’t tried it with the new will_paginate, but did get it going with the old paginator. Note that you have to indicate to SCH either sortasc or sortdesc in the passed parameters in a request, otherwise it’ll revert page to the default sort order defined in your sortable_order call (used to the call to paginate). On your next and previous links on your view, include either {:sortasc => params[:sortasc]} or {:sortdesc => params[:sortdesc]} (you only need one of these two – whichever arrived not nil from the previous request).

Ron F. at 11:21 PM on October 9 2007

I note that when using pagination, when one clicks on the sort header link, it loses the page parameter and goes back to 1.

Being a bit inexperienced with Rails, I am struggling to figure out how to get the page parameter into the sort_param call or the relevant link_to, since you can’t seem to pass both an href string and a set of params to link_to.

Has anyone solved this and are you willing to share the solution with me?

Thanks for the plugin, it’s very cool and has saved me a bunch of time.

Ron

Ron F. at 4:54 AM on October 10 2007

Okay, well, I fixed the pagination problem, but not the way I’d have liked to. I had to change line 207 of sortable_column_headers.rb to:

   1  { sort_param.to_sym => (got_chopped ? data_name : sortable_name+'-'+data_name), :page => params[:page] }

i.e. manually appended the current page to what is returned. I feel like I should have been able to do this directly in the link_to call in my view code, but I was unable (due to my inexperience, no doubt), to add the :page parameter after sort_params was called. I tried .merge(:params), but that merged ALL parameters everytime, and so that was undesirable.

Ron

Steve F at 10:34 PM on October 11 2007

Thanks for the feedback – I’ll try these out, and let you know how I get on. Steve

Xin at 12:30 PM on May 12 2008

In Firefox3, the plugin website would not display due to security certificate not matching.

script/plugin install does not work with the https address for me. I had to use http://svn.elctech.com/svn/public/sortable_column_headers

Is this Rails 2 compatible? I guess I’ll find out now!

Xin at 12:48 PM on May 12 2008

It is Rails 2 compatible after all. Nice job!

crazy at 10:42 PM on September 23 2008

How can I add a style to <= link_to ‘Awarding Body’,sort_param(‘listing’,AwardingBody,’name’)> <= link_to ‘Awarding Body’,:class=>”link_normal font_color” ,sort_param(‘listing’,AwardingBody,’name’)> can not run

crazy at 10:46 PM on September 23 2008

I found the problem <= link_to ‘Awarding Body’,sort_param(‘listing’,AwardingBody,’name’) , :class=>”link_normal font_color” > is ok. thanks for your plugin

Nwsxomrz at 12:22 PM on September 27 2008

real beauty page

Nuxvyhor at 3:27 PM on September 27 2008

Punk not dead

Jack at 12:17 PM on October 27 2008

Thanks for this awesome plugin. I’ve got it set up and working happily with the will_paginate plugin and a custom search implementation.

Question: how can I set it to default to sorting by multiple columns? Should I use the sessions[:sortable_column_headers] array, or is there a prettier way to do it?

Jack at 12:17 PM on October 27 2008

Thanks for this awesome plugin. I’ve got it set up and working happily with the will_paginate plugin and a custom search implementation.

Question: how can I set it to default to sorting by multiple columns? Should I use the sessions[:sortable_column_headers] array, or is there a prettier way to do it?

samotage at 6:32 AM on November 5 2008

Awesome sweet plugin. Even late in the evening after a few drinks this could be “sorted” even with will_paginate working…

BTW, is it possible to sort within the current pagination, I find it resets the whole shebam to the beginning.

Thanks again! Sam.

James at 12:42 PM on November 7 2008

I implemented this today and really love this plugin.

Noticed an odd thing with price however.

It would sort it like this

$4.00 $4.50 $4.99 $45.00 $5.00

Anything I can do to have it sort by more accurately?

Thanks

Add a comment


home | services | Ruby on Rails Development | code | blog | company