Order table by grouping values in another table - ruby-on-rails

I have a table of questions: title
Each question has answers, in another table: text, question_id
Each answer has votes, in another table: answer_id
I can ask for total votes with
question.votes.count
I have seen how to group the votes db at
http://guides.rubyonrails.org/active_record_querying.html#group
Vote.group("answer_id")
But I want to order my questions by votes. That is ordering an array from a table via the grouping of another table. Is that possible?
q=Question.last
q.answers.order_by_vote #How to do this?
I think my answer could be doing a scope on the answer model that makes the grouping on the subset of votes that belong to the question. Am I right?
Thank you.

First, I think that you mean table when you say DB (database). A table a structure inside a database that holds data for a specific model, for example (questions, votes and answers. In your case you have three tables.
Second, calling attr_accessible :answer_id does not make an attribute searchable by an index. It is searchable by this attribute regardless of whether or not you declare it accessible. It is not an index unless you specify it as an index in the database. attr_accessible means that the attribute can be set using mass-assignment, for example when you call update_attributes.
Finally, if you want to group by answer_id and order by the number of votes, you can do so with the following query:
Vote.select('count(id) as votes, answer_id').group('answer_id').order('votes DESC')
If you want to order by some other value than the one you are grouping by, you'll have to add that to your group as well. This ensures that you aren't getting arbitrary results for the second value. For example:
Vote.group('answer_id').group('column_1').order('column_1 DESC')

I just figured out a way to organize my links by vote count, using the sort method in my links view:
<% #user.links.sort { |a, b| b.votes.sum(:score) <=> a.votes.sum(:score) }.each do |link| %>
votes.sum(:score) grabs the number of votes a particular link has from the votes table.
hope that helps.

Related

Rails sort users by method

I'm trying to rank my user's in order of an integer. The integer I'm getting is in my User Model.
def rating_number
Impression.where("impressionable_id = ?", self).count
end
This gives each User on the site a number (in integer form). Now, on the homepage, I want to show an ordered list that places these user's in order with the user with the highest number first and lowest number second. How can I accomplish this in the controller???
#users = User....???
Any help would be appreciated!
UPDATE
Using this in the controller
#users = User.all.map(&:rating_number)
and this for the view
<% #users.each do |user| %>
<li><%= user %></li>
<% end %>
shows the user's count. Unfortunately, the variable user is acting as the integer not the user, so attaching user.name doesn't work. Also, the list isn't in order based on the integer..
The advice here is still all kinds of wrong; all other answers will perform terribly. Trying to do this via a nested select count(*) is almost as bad an idea as using User.all and sorting in memory.
The correct way to do this if you want it to work on a reasonably large data set is to use counter caches and stop trying to order by the count of a related record.
Add a rating_number column to the users table, and make sure it has an index defined on it
Add a counter cache to your belongs_to:
class Impression < ActiveRecord::Base
belongs_to :user, counter_cache: :rating_number
end
Now creating/deleting impressions will modify the associated user's rating_number.
Order your results by rating_number, dead simple:
User.order(:rating_number)
The advice here is just all kinds of wrong. First of model your associations correctly. Secondly you dont ever want to do User.all and then sort it in-memory based on anything. How do you think it will perform with lots of records?
What you want to do is query your user rows and sort them based on a subquery that counts impressions for that user.
User.order("(SELECT COUNT(impressions.id) FROM impressions WHERE impressionable_id = users.id) DESC")
While this is not terribly efficient, it is still much more efficient than operating with data sets in memory. The next step is to cache the impressions count on the user itself (a la counter cache), and then use that for sorting.
It just pains me that doing User.all is the first suggestion...
If impressions is a column in your users table, you can do
User.order('impressions desc')
Edit
Since it's not a column in your users table, you can do this:
User.all.each(&:rating_number).sort {|x,y| y <=> x }
Edit
Sorry, you want this:
User.all.sort { |x, y| y.rating_number <=> x.rating_number }

Rails 4: Displaying a table of a collection of items, sorted by various item attributes?

So I have a CareerEntry model that has the following attributes: name, job_category, company, group, location, year, full_intern, and it represents the job offers that people have received. full_intern is a string that is either "internship" or "full-time", and represents what the type of the job offer is. All CareerEntries will be created by an Admin interface, so it is essentially acting as a standalone model. This is my question: given a bunch of CareerEntry objects, I want to display a table to display on my careers page (which has an action in a PagesController).
I want the table to be sorted according to multiple attributes. I want each year to be its own section in the table, then within each year, I want the internship entries grouped together and the full-time entries grouped together. Then, within these groupings, I want each job_category to be its own section (job_categories comprise of things like 'Investment Banking,' or 'Technology.')
A very good example of what I'm going for is shown under the "2013" tab in this link.
What is the best way to go about achieving this? I know that in the careers action definition of my PagesController, I could have:
class PagesController < ApplicationController
def careers
#careerentries = CareerEntry.order(:year => :desc, :fullintern => :asc, :job_category => :asc)
end
end
But this would simply return all the entries in the order that I want, and would not allow me to place headers and dividers to separate, say, the job_categories.
Is there any easier way of achieving what I'm looking for?
Perhaps you're looking for .group_by?
Group By
From the link you gave, it looks like you want to group your results by year, like this:
#careerentries = CareerEntry.order(year: :desc, fullintern: :asc, job_category: :asc)
#entries_by_year = #careerentries.group_by { |entry| entry.year }
This gives you all the data, ordered to your specs. You can then sort through it, using the group_by method:
#entries_by_year.each do |entry|
entry.name
end
You could then work this into your table
Good reference Group posts by Year - Rails

How can I add a virtual "count" column to a select query in rails?

I have a post model, and post has_many :comments, :as => :commentable (polymorphic). I am looking for a way that I can fetch all posts, and have a virtual attribute on the record which will display how many comments belong to that post.
I was thinking that I could just do:
Post.select("posts.*, count(comments.id) as post_comments").joins(:comments)
However, that returns only one record, with post_comments set to ALL comments in the entire database, not just those belonging to the record...
Actually, what you are missing is a group clause. You need to group by site, otherwise the count() aggregation collapses everything to one record as you see.
Try this:
Post.select("posts.*, count(comments.id) as post_comments")
.joins(:comments)
.group('posts.id')
I think the problem is that your count(comments.id) just does one count for the entire joined table. You can get around this with a nested query:
Post.select("posts.*, (SELECT count(comments.id) FROM comments WHERE comments.post_id=posts.id) AS post_comments")
You don't need the join in this case, since the comments table is not used in the outer query.
I would do that with variables in Post model. 1st I would try to find the post I am looking for somehow (you can find it by wichever parameter you want,below I show the example with searching the id param).
#post = Post.find(params[:id])
When you find the post you were looking for, finding out comment number is preety easy, try something along the lines of...
#comments = #post.comments.size
...wich would return an integer.

Sorting and searching on a field which model doesn't have

I have an HTML table where I show the data from a particular model but I also show a column in the HTML table which doesn't belongs to that model. this column comes after some calculation(In this calculation I use 3-4 more tables). I want to give the sorting and searching functionality on that column. Anyone having idea what is the best way to do that?
Updated:
The main problem is if I provide sorting/searching on that column then I have to fetch all records from database for calculation which will not be good idea.
If you are looking for performance solution: just add new field into your table to store your calculation.
Anyway, you can't solve your problem without fetching all your records.
Or you can use JavaScript for searching and sorting, but only if there are not many items.
You can sort you model:
q_new.sort! { |x, y|
y.creation_date <=> x.creation_date
}
creation_date is a any field or a method of the model.
I would create a virtual resource on the model, which contains the sorter in Ruby-code. Assuming sum is your virtual property.
def by_sum(options = {})
#items = self.class.find(options)
#items.sort! { |a,b| a.sum <=> b.sum }
end
In your controller you can call:
Item.by_sum({:where => "'foo' = 'bar'"})

How to print all elements that belongs_to this table

Ok, I'm not sure that my title was clear enough, but I will try to explain
I have two tables: orders that has_many items and items that belongs_to orders.
I just started to learn RoR and stuck with a simple task. All I want is to
display orders and related items like this:
Order 1:
Item 1
Item 2
Order 2:
Item 1
Item 2
...
I know how to display orders or items separately, I know how to display items' orders (item.order.id), but how to display orders and items in the table like above? In template where I display orders I could go through each item every iteration and compare it foreign order_id with order.id, but that would be awkward. I'm supposing that I should get items into some kind of multidimensional hash where key would be order_id and then I could just refer to this hash by order id and get all items in it, but I'm not sure it's correct.
I hope what I have written here is understandable.
When you define a has_many relation, you automatically get the methods to query those objects. In this case, the method order.items.
So you can do:
Order.find_each do |order|
puts "Order #{order.id}:"
order.items.each do |item|
puts "Item #{item.id}"
end
end
(I used find_each method, which is available from Rails 2.3+. You could use a simple Order.all.each though.

Resources