Question

I currently have a voting system implemented in my app and I'm sorting the posts by number of votes with this code in my view:

  <%= render @posts.sort_by { |post| post.votes.count }.reverse %> 

I want to sort by number of votes for each post by also don't want the post to be any more than lets say 5 days old. How can I sort the posts by both number of votes and date simultaneously.

Was it helpful?

Solution 5

I figured out another way to do it although I appreciate your help it may not be the cleanest way but I did

   def most
     range = "created_at #{(7.days.ago.utc...Time.now.utc).to_s(:db)}"
     @posts = Post.all(:conditions => range)
     @title = "All Posts"
     @vote = Vote.new(params[:vote])

     respond_to do |format|
       format.html
       format.json { render :json => @users }
     end
   end 

for my controller

created a route of /most :to => 'posts#most'

and made a view with the original code I had in my view.

I know its not the best way but I am still new to coding so its the best way I could figure out how.

OTHER TIPS

This is wrong. You should do all sorting operation on the database side. For this example consider using Arel for creating complex queries or consider create counter cache column.

You could just add a scope to your posts model, something like:

scope :five_days_ago, lambda { where("created_at >= :date", :date => 5.days.ago) }

Then just adjust your render method to the following:

<%= render @posts.five_days_ago.sort_by { |post| post.votes.count }.reverse %>

This assumes you want to keep the structure you are using. Obviously, as other suggested, doing it all in the database is the best course of action.

luacassus is right. It's better do delegate the sorting to the database for at least two reasons:

  1. Performance
  2. You can chain more query methods onto it (necessary for pagination, for example).

The counter cache is probably the best idea, but for the complex query, let me give it a shot. In your Post model:

class << self
  def votes_descending
    select('posts.*, count(votes.id) as vote_count').joins('LEFT OUTER JOIN votes on votes.post_id = posts.id').group_by('posts.id').order('votes_count desc')
  end

  def since(date)
    where('created_at >= ?', date)
  end

end

So...

@posts = Post.votes_descending.since(5.days.ago)

Indeed it will be better to let the db do the sorting. I would do something like

class Post < ActiveRecord::Base
  default_scope :order => 'created_at DESC'
end

then you will always have your posts sorted and if I'm not mistaken the last one should be the first you get, so that substitutes your 'reverse' call. Then you can use the scope posted above to get only 5 days old posts. Also check that there is an index on the created_at column in the db. You can do this with

SHOW INDEX FROM posts

The db will do this much faster than ruby.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top