Question

I've implemented a Star Rating System using this tutorial http://eighty-b.tumblr.com/post/1569674815/creating-an-ajaxified-star-rating-system-in-rails-3

Everything works in the SHOW PAGE, But in the INDEX PAGE, the JavaScript does not work. When the page is loaded, Every Book in the index page has the same rating as the first Book and it doesn't load the correct Star Rating to each book on the page.

(Am I missing something in the beginning of my JavaScript code, like an ID?)

New to rails please help :)

JAVASCRIPT

rating_ballot.js

### Sets up the stars to match the data when the page is loaded. 
### But applies the first Books Rating to all

$(function () {
  var checkedId = $('form.rating_ballot > input:checked').attr('id');
  $('form.rating_ballot > label[for=' + checkedId + ']').prevAll().andSelf().addClass('bright');
});

$(document).ready(function() {

    ### Makes stars glow on hover.
  $('form.rating_ballot > label').hover(
    function() {    // mouseover
        $(this).prevAll().andSelf().addClass('glow');
    },function() {  // mouseout
        $(this).siblings().andSelf().removeClass('glow');
  });

  ### Makes stars stay glowing after click.
  $('form.rating_ballot > label').click(function() {
    $(this).siblings().removeClass("bright");
    $(this).prevAll().andSelf().addClass("bright");
  });

  ### Submits the form & saves data.
  $(document).on('change', '.rating_button', function(){
    $(this).parent().submit();
  });
});

CSS.SCSS

form.rating_ballot input.rating_button { display: none; }

form.rating_ballot label.rating { cursor: pointer; display: block; height: 20px; width: 20px; float: left; }
form.rating_ballot label.rating span { display: none; }
form.rating_ballot label.rating { background-image:  image-url('star-dim.png'); }
form.rating_ballot label.rating.bright { background-image:  image-url('star-bright.png'); }
form.rating_ballot label.rating.glow { background-image:  image-url('star-glow.png'); }

VIEWS

show.html.erb (show)

<div id="book<%= @book.id %>">
 <div id="rating">
   <%= render :partial => 'ratings/rating', :locals =>{:book => @book} %>
 </div>
</div>

index.hrml.erb (books)

<% @books.each do |book| %>
  <table id="book<%= book.id %>">
    <tbody>  
      <tr>  
        <td>
          <%= book.title %>
        </td> 
      </tr> 

      <tr>

        <td  id="rating">                   
          <%= render :partial => 'ratings/rating', :locals =>{:book => book} %>
        </td>

      </tr>
    <tbody>
  </table>
<% end %>

_rating.html.erb

<%= form_for(rating_ballot(issue.id), :html => { :class => 'rating_ballot' }, remote: true ) do |f| %>

  <%= f.label("value_1", content_tag(:span, '1'), {:class=>"rating", :id=>"1"}) %>
  <%= radio_button_tag("rating[value]", 1, current_user_rating(issue.id) == 1, :class => 'rating_button') %>

  <%= f.label("value_2", content_tag(:span, '2'), {:class=>"rating", :id=>"2"}) %>
  <%= radio_button_tag("rating[value]", 2, current_user_rating(issue.id) == 2, :class => 'rating_button') %>

  <%= f.label("value_3", content_tag(:span, '3'), {:class=>"rating", :id=>"3"}) %>
  <%= radio_button_tag("rating[value]", 3, current_user_rating(issue.id) == 3, :class => 'rating_button') %>

  <%= f.label("value_4", content_tag(:span, '4'), {:class=>"rating", :id=>"4"}) %>
  <%= radio_button_tag("rating[value]", 4, current_user_rating(issue.id) == 4, :class => 'rating_button') %>

  <%= f.label("value_5", content_tag(:span, '5'), {:class=>"rating", :id=>"5"}) %>
  <%= radio_button_tag("rating[value]", 5, current_user_rating(issue.id) == 5, :class => 'rating_button') %>

  <%= hidden_field_tag("issue_id", issue.id) %>
  <%= f.submit :Submit, style: "display: none" %>
<% end %>

create.js.erb & update.js.erb

$('#issue<%= @issue.id%> #rating').html("<%= escape_javascript(render :partial => 'ratings/rating', :locals => {:issue => @issue}) %>");

CONTROLLER

class RatingsController < ApplicationController
  before_filter :current_user, only: [:create, :update]

  respond_to :html, :js

  def create
    @book = Book.find_by_id(params[:book_id])
    @rating = Rating.create(params[:rating])    
    @rating.book_id = @book.id
    @rating.user_id = current_user.id
    if @rating.save
      respond_to do |format|
        format.js
        format.html { redirect_to :back }
      end
    end
  end

  def update
    @book = Book.find_by_id(params[:book_id])
    @rating = current_user.ratings.find_by_book_id(@book_id)
    if @rating.update_attributes(params[:rating])
      respond_to do |format|
        format.js
        format.html { redirect_to :back }
      end
    end
  end

end

HELPERS

module IssuesHelper

  def rating_ballot(issue_id)
    if @rating = current_user.ratings.find_by_issue_id(issue_id)
        @rating
    else
        current_user.ratings.new
    end
  end

  def current_user_rating(issue_id)
    if @rating = current_user.ratings.find_by_issue_id(issue_id)
       @rating.value
    end
  end

end
Was it helpful?

Solution

The problem seems to be here:

$(function () {
  var checkedId = $('form.rating_ballot > input:checked').attr('id');
  $('form.rating_ballot > label[for=' + checkedId + ']').prevAll().andSelf().addClass('bright');
});

It gets the id of the first checked input, and for all forms sets the star rating to that one.

Try this code:

$(function () {
    $('form.rating_ballot').each(function() {
        var $form = $(this),
              checkedInput = $form.find('input:checked');

        checkedInput.prevAll().andSelf().addClass('bright');
    });
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top