| 1. | Herb | my website | 05/28/2007 14:22:38 |
Seeing as its the first google hit and no one has posted a comment... thanks works great for me!
Of all the things I hate doing, column sorting has to be top on my list. It always seems to be more difficult than it should be. Here's my take on a really simple way to implement column sorting for your Rails application. I call it Super Cool Simple Column Sorting, or SCSCS. That's pronounced 'ssssssss'.
The first part is the HTML helper.
def sort_link(title, column, options = {})
condition = options[:unless] if options.has_key?(:unless)
sort_dir = params[:d] == 'up' ? 'down' : 'up'
link_to_unless condition, title, request.parameters.merge( {:c => column, :d => sort_dir} )
end
It takes the title you wish to display, the name of the column you wish to sort, and any extra options you wish to add to the link. You can also pass an :unless flag to turn the link on or off. Put this in a helper somewhere, maybe application_helper.rb.
To use it...
<%= sort_link 'Company', :company_name %>
This will default to sorting up, or ASC, and will toggle up or down automatically.
Now you just need the SQL helper.
def sort_order(default)
"#{(params[:c] || default.to_s).gsub(/[\s;'\"]/,'')} #{params[:d] == 'down' ? 'DESC' : 'ASC'}"
end
Put this somewhere the controller can see it, maybe application.rb. Then just call it in the query in your controller.
def list
@applications = Application.find(:all, :order => sort_order('created_at'))
end
The sort_order method takes the default column you wish to sort on.
I really like this simple helper based approach. It's not quite as slick as making a plugin, but it's easier to tweak it for different cases, and less than 10 lines.
| 1. | Herb | my website | 05/28/2007 14:22:38 |
Seeing as its the first google hit and no one has posted a comment... thanks works great for me!
| 7. | Rich Allen | my website | 12/16/2007 05:59:34 |
Exactly what I have been looking for, thanks!
| 10. | Ljuba | 07/23/2008 19:52:20 |
Question: How do I sort by something's name when all I have is their ID number.
Say, if in addition to being able to sort by company name I'd like to sort by a value not contained in that model, but was identified by ID in a linking table.
How would the following line of code be different?
<%= sort_link 'Company', :company_name %>
The line of code above expects there to be parameter called company_name in whatever model you're talking about. All I have is an ID that links to another model.
Any help?
| 13. | Ben | 09/10/2008 13:36:27 |
That's cool, it wouldn't work in this instance however, because pagination is required. Javascript pagination wouldn't work either, cause loading 8000 records and parsing xml for each of them is not good for the environment.
I wish I had found dojocampus a week ago. I tried out dojo and got so frustrated trying to find documentation and examples I just went back to Prototype.
| 15. | JVandaL | 12/09/2008 16:08:19 |
Also what about sorting on multiple fields. If I do the following
find(:all, :order => sort_order('first, second, third')
the sort_order helper generates this in the SQL
ORDER BY first,second,third ASC
but it seems to only be ordering by first not any of the others...
Any help?
| 16. | JVandaL | 12/09/2008 18:57:17 |
I figured out a solution. It's kind of ugly but it seems to work ok.
def sort_order(default)
# allows for more than one column to sort on
sql_order = [ ]
sort_array = (params[:c] || default.to_s).gsub(/[\s;'\"]/,'').split(/,/)
sort_array.each do |c|
sql_order << c + " #{params[:d] == 'down' ? 'DESC' : 'ASC'}"
end
sql_order.join(', ')
end
and for my first question about associations I did this
[...] .find(:all, :include => [:customer], :order => sort_order('created_at'))
and then with both of these changes I could do this
<%= sort_link 'Customer', 'customers.first_name, customers.last_name' %>
I know this is an old blog entry, but if anyone is out there I'd love any feed back.
| 19. | Lukas Oberhuber | my website | 03/17/2009 08:46:15 |
I think the sort_link function needs a small change to get default sorting order working:
def sort_link(title, column, options = {})
condition = options[:unless] if options.has_key?(:unless)
sort_dir = options[:d] if options.has_key?(:d)
sort_dir = params[:d] == 'up' ? 'down' : 'up' if params[:d]
link_to_unless condition, title, request.parameters.merge( {:c => column, :d => sort_dir} )
end
| 20. | Alfie | 06/04/2009 08:50:36 |
This is exactly what I need. However, I'm having a few issues. My 'find' is in the model:
-------------
def find_products
scope = Model.scoped({:order => sort_order('attribute_1')})
scope = scope.scoped :conditions => ...
end
def sort_order(default)
"#{(params[:c] || default.to_s)} #{params[:d] == 'down' ? 'DESC' : 'ASC'}"
end
----------
My problem is that I can't figure out how to pass params to the model. It doesn't recognize it as a method or variable and I don't completely understand the last line in the sort_link method (ink_to_unless condition, title, request.parameters.merge( {:c => column, :d => sort_dir} )). What is the best way to get this to work? Any advice would be appreciated. Otherwise, thanks for the headstart in tackling this.
| 21. | julianvg | 10/11/2009 15:03:29 |
Hi,
Thanks for the useful posts and comments!
I had a requirement to sort a column with IP addresses that MySQL couldn't sort satisfactorily.
So instead of using Ben's sort_order helper, I used the following code in my controller:
@customers = Customer.find(:all)
case params[:c]
when nil then @customers.sort! {|x,y| x.username <=> y.username }
when "tunnel" then @customers.sort! {|x,y| IPAddr.new(x.send(params[:c])) <=> IPAddr.new(y.send(params[:c]))}
else @customers.sort! {|x,y| x.send(params[:c]) <=> y.send(params[:c])}
end
case params[:d]
when "up" then @customers
when "down" then @customers.reverse!
end
I had to enclose the IPAddr.new() within begin/rescue clauses to deal with nil values and other non-standard values (my model allows for this).
I'm new to Ruby and Rails so I'm not sure this is the most elegant code but it worked for me.
Post a Comment