Search code examples
ruby-on-railshamlraty

Show pin/post average rating in index Ruby on Rails and Raty.js


I've used Ruby on Rails and Raty.js to create a rating system for my pins. You can see the average rating in the individual Show pages for each pin. I'd like to incorporate that into my index file. Currently, the rating that is showing for all pins in the index is the average rating of the first pin.

Note: I'm using Haml for the index file, but if you could provide an answer in basic html, that'll be fine.

index.html.haml:

.panel-footer
  .btn-group.pull-left
    %div{class: "srating", dscore: @avg_review }

:javascript
    $('.srating').raty({
        path: '/assets/',
        readOnly: true,
        score: function() {
            return $(this).attr('dscore');
        }
    });

pins_controller.rb:

class PinsController < ApplicationController
    before_action :find_pin, only: [:show, :edit, :update, :destroy, :upvote, :un_upvote]
    before_action :authenticate_user!, except: [:index, :show]

    def index
        @pins = Pin.all.order("created_at DESC").paginate(page: params[:page], per_page: 7)
        for singlepin in @pins
            @stars_reviews = StarsReview.where(pin_id: singlepin.id)

            if @stars_reviews.blank?
                @avg_review = 0
            else
                @avg_review = @stars_reviews.average(:rating).round(2)
            end
        end
    end

Solution

  • It's actually showing the average rating for the last pin.

    for singlepin in @pins
      @stars_reviews = StarsReview.where(pin_id: singlepin.id)
    
      if @stars_reviews.blank?
        @avg_review = 0
      else
        @avg_review = @stars_reviews.average(:rating).round(2)
      end
    end
    

    Each loop here is just setting the one variable to the new value.

    So either add an average rating attribute on pin and update it everytime someone rates it.

    Or make the variable an array:

    @avg_reviews = []
    for singlepin in @pins
      @stars_reviews = StarsReview.where(pin_id: singlepin.id)
    
      if @stars_reviews.blank?
        @avg_reviews << 0
      else
        @avg_reviews << @stars_reviews.average(:rating).round(2)
      end
    end
    

    Then output as you loop over the pins

    <% @pins.each_with_index do |pin, i| %>
      %div{class: "srating", dscore: @avg_reviews[i] }
    <% end %>
    

    Or you could allow an attribute on pin that you set

    class Pin
      attr_accessor :avg_review
    end
    
    for singlepin in @pins
      @stars_reviews = StarsReview.where(pin_id: singlepin.id)
    
      if @stars_reviews.blank?
        singlepin.avg_review = 0
      else
        singlepin.avg_review = @stars_reviews.average(:rating).round(2)
      end
    end
    

    Then access it in the view

    <% @pins.each do |pin| %>
      %div{class: "srating", dscore: pin.avg_review }
    <% end %>