4

My app has designs that users can like (vote, using acts_as_voteable). To find a design's like count in the view, you use

@design.votes.count

I'm making a popular page to showcase the most popular designs based on the number of votes they have. I only want designs that has at least 5 votes to them. Right now, I had that in the view but I want to push that into the controller. My controller, thus far, looks like this which shows all the designs and sorts them in order of most votes.

def popular
  @designs = Design.all
  @designs.sort! {|t1, t2| t2.votes.count <=> t1.votes.count}
end

Now i just want to make sure the designs have a minimum vote count of 5.

Previously, I was doing this the wrong way and putting it in my view by putting this inside my Design loop

<% if design.vote.count > 5 %>
  ...
<% end %>

Thanks!

2 Answers 2

4
+50

First of all, the behavior you want is better defined in the Design model and not in the controller since it deals with data. So in your Design model, add the following code:

scope :most_popular, -> do 
  results = select {|design| design.votes.count > 4 }
  results.sort! {|t1, t2| t2.votes.count <=> t1.votes.count}
end

Adding the two scope methods above in your Design model, you could do this in your controller code:

def popular
  @designs = Design.most_popular
end

Your controller code ends up being a lot cleaner and you have scope methods that you can reuse anywhere else you need them. :)

Hope that helps!

Sign up to request clarification or add additional context in comments.

3 Comments

Yes! that's it! Thanks so much @Gjaldon! You definitely helped solve the problem and now it's clear to put that behavior in the model. Much appreciation. Enjoy the bounty when it lets me award it in about 9 hours
Now I will say the order_by_popularity isn't working in the model but when I put that code into the controller like I had it, it works. Right now I have @designs = Design.most_popular @designs.sort! ..... and that works, but the Design.most_popular.order_by_popularity gives me this error undefined method "order_by_popularity" for #<Array:0x0000010260e5c0>
I'm glad you find it useful! Looks like most_popular is returning an array so I'll just move it inside the :most_popular scope method instead.
2

You can use a having() clause. See: http://guides.rubyonrails.org/active_record_querying.html#having

For example: Design.joins(:votes).group('votes.design_id').having('votes.count > 5').order('votes.count')

Edit

You can also just use a where clause. For example, for the first design:

Design.first.votes.where('count > 5')

Example for multiple designs:

Design.all.map{ |a| a.votes.where('count > 5').count }.sort! # returns a sorted array with all vote counts

10 Comments

Thanks for your reply, I'm actually getting an error with that and I've tried a few different things like that but keep getting an error each time. PG::GroupingError: ERROR: column "designs.id" must appear in the GROUP BY clause or be used in an aggregate function
Did you actually setup your relationship? As in: a Design has_many :votes and a Vote belongs_to :design. The vote table should have a design_id.
With the acts_as_voteable gem, to setup the relationship in the DesignModel you just use acts_as_voteable
Votes have a voteable_id and voteable_type as it's polymorphic because multiple models get voted on. To make the problem easier, I just asked about one model, Design, to find that query
I forgot grouping. You need to group before using having. P.s. You can use whatever you want as grouping column, I just gave an example.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.