views:

24

answers:

2

Let's say I run an ActiveRecord query and it returns 3 results, with a bunch of attributes.

I want to add 3 attributes to each record in the Array so I can do sorting at a code-level. These 3 include: num_comments, num_views, last_view.

  1. How do I add these attributes?
  2. How do I then sort the records, in order of precendence, by num_comments AND by num_views AND by last_view?
+2  A: 
# file a_model_class (AR subclass)
   attr_accessor :num_comments, :num_views, :last_view # add setters and getters

# different file that is doing the fetch and sort...
results = AModelClass.find.... # 3 results
results.each{|r|
  r.num_comments = x  # set the instance variables for sorting
  r.num_views = y
  r.last_view = z
}

# now sort
sorted_results = results.sort{|a,b|
  r = a.num_comments <=> b.num_comments 
  r = a.num_views <=> b.num_views if r == 0
  r = a.last_view <=> b.last_view if r == 0
}

# sorted_results is sorted copy of results
Larry K
sorting can be optimized into simple `sorted_results = results.sort_by{ |r| [r.num_comments, r.num_views, r.last_view] }`
zed_0xff
A: 

Expanding on Larry K's answer and zed_0xff's comment, why even create attributes, just sort by a method in your model:

class Widget < ActiveRecord::Base
  def num_comments
    #count comments
  end

  def num_views
    #count views
  end

  def last_view
    #return last view
  end
end

in your controller

class WidgetsController < ApplicationController
  def index
    @widgets = Widget.all.sort_by{ |r| [r.num_comments, r.num_views, r.last_view] }
  end
end
Patrick Klingemann
Main thing to watch out for here is to NOT re-compute the values (num_comments, etc) each time the methods (num_comments, etc) are called. Since those methods will be called many times during the sort, they need to cache their values. Using instance variables will explicitly ensure this. I agree with you that the computation of the values should probably be handled from within the model, not externally.
Larry K
Ahhh, good point, I didn't even think of that. I'll refactor my answer a bit.
Patrick Klingemann