The ELC Community Blog
A knowledge exchange on Ruby on Rails and Agile Development
sortable column headers
by cnady on May 08, 2007
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/
Timeline
- RailsConf Europe
- Why associated models don't save
- RailsConf 2007 Highlights
- RailsConf 2007 - Day 1
- Don't mix attr_protected and attr_accessible.
- sortable column headers
- DRY validates_inclusion_of with introspection
- HTTP Auth with Restful Authentication
- TuneCore covered on TUAW!
- TabTerm Release
- write_inheritable_attribute.............. and friends !
Comments
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.
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!
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.
Thanks Sean! Yeah, sloppy cut-n-paste on my part. I have updated SCH as of this comment. Cheers!
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?
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
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:)
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!
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:
Howdy arash! Yes, you can definitely sort on associations. An example of this exists in the plugin’s accompanying README file.
Thanks got it!
Any way to sort a ferret index return (using acts_as_ferret)?
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.
That did it! Thanks cnady!
Hi,
Can anybody explain me how to patch/install this plugin to the alreday existing application?
Thanks & Regards reddy g.p
Howdy reddy! Please see my response to Chase on June 15.
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
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.
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:
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
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?
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?
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```
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).
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! :)
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/
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
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```
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.
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.
To our friends’s help,i solve the problem.Thanks for your plugin.I really like it.
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!
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!
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…
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.
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
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.
Great, great plugin, big thanx!
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?
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.
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?
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).
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
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:
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
Thanks for the feedback – I’ll try these out, and let you know how I get on. Steve
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!
It is Rails 2 compatible after all. Nice job!
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
I found the problem <= link_to ‘Awarding Body’,sort_param(‘listing’,AwardingBody,’name’) , :class=>”link_normal font_color” > is ok. thanks for your plugin
real beauty page
Punk not dead
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?
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?
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.
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
Hey, this is a pretty awesome plugin. I’ve used it in Rails 2.0 apps, but have recently upgraded to 2.1 and now get:
“You have a nil object when you didn’t expect it! You might have expected an instance of ActiveRecord::Base. The error occurred while evaluating nil.[]=”
On my add_to_sortable_columns line. All I’m doing on that line is this: add_to_sortable_columns(‘listing’, UnapprovedPhoto)
Do you know if there are any compatibility issues between the plugin and Rails 2.1?
Thanks a lot! Chelsea