Tetramputechture
Tetramputechture

Reputation: 2921

Get average of attribute through 'has_many'

I have two models at play here, a Tab, and a Rating.

A Tab has_many Ratings, and each Rating belongs_to one Tab; each Rating has a value between 1 and 5.

Here are my models, with the relevant code:

tab.rb

class Tab < ApplicationRecord
  ...
  has_many :ratings, dependent: :destroy
  ...
end

rating.rb

class Rating < ApplicationRecord
  ...
  belongs_to :tab
  ...
end

And this is how my index view is displayed:

https://i.sstatic.net/TXmSo.png

with the Rating column being the average rating value of the tab.

Right now, to get each tab's average rating, I'm executing a query for each tab's average rating. This is very slow, and I am looking to improve this.

Here's my controller, with the relevant method as it is:

tabs_controller.rb

class TabsController < ApplicationController
  ...
  def index
    # need to display average rating
    # don't want to do one query for each tab
    # so, make index return a table that includes avg rating as a column
    @tabs = Tab.all
  end
  ...
end

These are all the queries generated when I load the tab index page:

enter image description here

I think that I will need to execute a query in the index controller method that returns a table including all the tabs, and the average rating of each of those tabs. How would I do this?

I might also need to use a view. If anyone could lead me in the right direction, that would be very appreciated.

Upvotes: 3

Views: 640

Answers (2)

olucube.com
olucube.com

Reputation: 340

I have used jQuery Raty before here.

To compute average rating in your TabsController show action you can add this

...
@ratings = Rating.where(tab_id: @tab.id)
if @tab.ratings.any?
    @avg_rating=@tabs.average(:value).round(2)
 else
    @avg_rating=0
end


...

and to display it in show page

<div class="start-rating" data-score= <%= @avg_rating %> ></div>

but in the index page, do this

<div class="start-rating" data-score= <%= tab.ratings.average(:value) %> > </div>

Upvotes: 0

Rahul Sharma
Rahul Sharma

Reputation: 1431

Try using this. this will work

Tab.joins(:ratings).select("tabs.*, AVG(ratings.value) AS average_ratings").group("tab.id") 

Upvotes: 3

Related Questions