Finding and Sorting

I am just trying to work through David Black's block of code from Ruby For Rails, on page 80.

def all   @order = params[:order] || "number"   sort_proc = case @order     when "author" then lambda {|r| [r.user.name.downcase, r.number] }     when "status","title" then lambda {|r| [r.send(@order).downcase, r.number]}     when "number" then lambda {|r| -r.number }   end   @rcrs = Rcr.find(:all).sort_by &sort_proc end

I can get this to work just fine. But how about this...if the user passes the "order" parameter as author, I want to sort nearly the same way, but with r.user.name descending. I know this errors, but I mean something like:     when "author" then lambda {|r| [r.user.name.downcase DESC, r.number] }

How do you control the ascending/descending on one of the two sort parameters?

Also, in the "number" sort option, what is the - doing in the part -r.number? I have experimented with it, but haven't determined what it is doing.

Thanks, Rob

I hadn't seen this code but it was a good exercise to figure out what was going on. Here's how it looks to me:

(1) as for the ascending, descending, probably it would be easiest to simply throw a .reverse on the end of that string. This code doesn't seem to be aimed at efficiency so much as clarity (I'd rather use the database to take care of ordering in the find), so I don't think the extra method call is too heavy.

(2) the -r.number is a way of sorting descending ([1,2,3] becomes [-3,-2,-1])

I was happy to learn the array trick with sort_by from this example though. Sort sorts arrays according to their content values, starting from first to last (so [[1,2],[3,4],[3,2]].sort evals to [[1,2],[3,2],[3,4]]. This example then uses arrays as the sort_by map to sort by various criteria.

Still, I don't understand why one would go this way instead of letting the database do the sorting.

Ethan

mazurr@gmail.com wrote:

I can get this to work just fine. But how about this...if the user passes the "order" parameter as author, I want to sort nearly the same way, but with r.user.name descending. I know this errors, but I mean something like:     when "author" then lambda {|r| [r.user.name.downcase DESC, r.number] }

How do you control the ascending/descending on one of the two sort parameters?

The easiest way to sort descending is to use the regular .sort method and reverse the variables coming from the block:

["a","b","c"].sort { |x,y| y <=> x } #=> ["c","b","a"]

For sorting my case insensitive name in reverse, it would look like:

Author.find(:all).sort { |x,y| y.name.downcase <=> x.name.downcase }

If you do this a lot you could make a method for it (I don't think one already exists):

class Array   def sort_by_reverse(&block)     sort { |x,y| block.call(y) <=> block.call(x) }   end end

Then: ["a","B","c","D"].sort_by_reverse { |s| s.downcase } #=> ["D","c","B","a"]

I'm not sure if this is the most efficient way, or if .sort.reverse if more efficient, but it works.

Dan Manges