开发者

rails 3 + active record: is there a clever way to "round robin" the order of records

(the actual numbers are 100x larger, but its easier to explain as follows)

we have a record set of 100 reviews for 5 restaurants. Some restaurants have 3 or 4 reviews, some have 20-30 reviews.

currently I have a simple report that arranges them from newest to oldest:

@reviews = Review.joins(:store). 
where('reviews.published= ?',true). 
order("reviews.created_at DESC")

For one of my report views, I need to display the reviews in round-robin order that ensures each restaurant gets equal coverage at the top of the list.

most recent for restaurant #A 
most recent for restaurant #B 
...
most recent for restaurant #E

then repeat for the next-most-recent for #A, #B,... #E

etc

Ideally the order of the round-robin would be which restaurant has the most total reviews.

It's not hard to do it the slow way in code, but I'm wondering if there's a faster/better activerecord approach?

===

Is there a way to (a) sort by restaurant, (b) create a temporary "counter" column that counts from 1 to N for each entry for each restaurant, (c) re-sort on that counter column? That would do it.

For example, after (a) and (b) the recordset would be

A , <some review>, 1
A , <some review>, 2
...
A , <some review>, 23

B , <some review>, 1
B , <some review>, 2
...
B , <some review>, 11

C , <some re开发者_如何转开发view>, 1
C , <some review>, 2
...
C , <some review>, 9

If I could then sort that recordset on the counter, it would round-robin A,B,C, etc


You can add a column in the DB last_displayed, update that with each display of the restaurant and always sort .order('last_displayed').

I also think you could use the updated_at column, touch the record after displaying it, and sort by that column - this way you won't need to update your DB structure


I recently implemented something similar to this. In my model I created this method:

def self.order_jobs
        ordered_jobs = []
        jobs = Job.all.to_a
        jobs.each do |j|
            ordered_jobs.push jobs.delete_at(jobs.find_index {|j| j.company == 'Redhat'}) unless (jobs.find_index {|j| j.company == 'Redhat'}).nil?
            ordered_jobs.push jobs.delete_at(jobs.find_index {|j| j.company == 'Zapier'})    unless (jobs.find_index {|j| j.company == 'Zapier'}).nil?
            ordered_jobs.push jobs.delete_at(jobs.find_index {|j| j.company == 'Mozilla'}) unless (jobs.find_index {|j| j.company == 'Mozilla'}).nil?
            ordered_jobs.push jobs.delete_at(jobs.find_index {|j| j.company == 'Ubuntu'})    unless (jobs.find_index {|j| j.company == 'Ubuntu'}).nil?
            ordered_jobs.push jobs.delete_at(jobs.find_index {|j| j.company == 'Digital Ocean'}) unless (jobs.find_index {|j| j.company == 'Digital Ocean'}).nil?
        end
        ordered_jobs
    end

Then in the controller I simply call Job.order_jobs like this:

def index
    @jobs = Job.order_jobs
  end

In the order_jobs method I start by creating two arrays. One with the existing jobs in the DB (jobs) and another (ordered_jobs) where I will move the jobs to in a round robin order. The magic is in ordered_jobs.push jobs.delete_at(jobs.find_index {|j| j.company == 'Redhat'}); this says find a job with the company Redhat and move it from the jobs array to the ordered_jobs array. the unless and .nil? sillyness allows you to move past that code once the jobs array no longer has elements that fit the given criteria.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜