Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeError (nil can't be coerced into Float):

Im trying to implement ratings system. Going through this tutorial

I keep getting this error when i try to give a rating:

Started PATCH "/ratings/7.json" for 127.0.0.1 at 2014-10-31 14:09:58 +0200
Processing by RatingsController#update as JSON
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"j/bCg3mFtQLl1n5qSZInNrUoKaRT/PKpzLnEz6QNGcQ=", "rating"=>{"book_id"=>"1", "user_id"=>"1", "stars"=>"4"}, "id"=>"7"}
  User Load (0.4ms)  SELECT  "users".* FROM "users"  WHERE "users"."id" = 1  ORDER BY "users"."id" ASC LIMIT 1
  Rating Load (0.2ms)  SELECT  "ratings".* FROM "ratings"  WHERE "ratings"."id" = $1 LIMIT 1  [["id", 7]]
   (0.1ms)  BEGIN
   (0.2ms)  COMMIT
  Book Load (0.2ms)  SELECT  "books".* FROM "books"  WHERE "books"."id" = $1 LIMIT 1  [["id", 1]]
  Rating Load (0.3ms)  SELECT "ratings".* FROM "ratings"  WHERE "ratings"."book_id" = $1  [["book_id", 1]]
Completed 500 Internal Server Error in 8ms

TypeError (nil can't be coerced into Float):
  app/models/book.rb:30:in `+'
  app/models/book.rb:30:in `block in avg_rating'
  app/models/book.rb:29:in `avg_rating'
  app/controllers/ratings_controller.rb:37:in `block (2 levels) in update'
  app/controllers/ratings_controller.rb:35:in `update'

My show.html.erb view:

<% form_id = "book_#{@book.id}_rating" %>
<% if user_signed_in? %> <!-- To avoid throwing an exception if no user is signed in -->
    <% user_id = current_user.id %>
<% else %>
    <% user_id = -1 %>
<% end %>
<%= form_for @book.ratings.find_or_create_by(user_id: user_id), :html => {:id => form_id, :class => "star_rating_form"} do |f| %>
    <%= f.hidden_field :book_id, :value => @book.id %>
    <% if user_signed_in? %>
        <%= f.hidden_field :user_id, :value => current_user.id %>
    <% end %>
    <%= f.hidden_field :stars, :id => form_id + "_stars" %>
<% end %>
<% (1..5).each do |i| %>
    <li class="rating_star" id="<%= form_id %>_<%= i %>" data-stars="<%= i %>" data-form-id="<%= form_id %>"></li>
<% end %>

My ratings_controller.rb:

  before_filter :js_logged_in

  def create
    @rating = Rating.new(rating_params)
    @book = Book.find(params[:rating][:book_id])

    respond_to do |format|
      if @rating.save
        format.json { render :json => { :avg_rating => @book.avg_rating } }
      else
        format.json { render :json => @rating.errors, :status => :unprocessable_entity }
      end
    end
  end

  def update
    @rating = Rating.find(params[:id])

    respond_to do |format|
      if @rating.update_attributes(rating_params)
        format.json { render :json => { :avg_rating => @rating.book.avg_rating } }
      else
        format.json { render :json => @rating.errors, :status => :unprocessable_entity }
      end
    end
  end


  def js_logged_in
    if(!user_signed_in?)
      flash[:error] = "You must be a signed in to leave a rating!"
      render :js => "window.location = '/users/sign_in'"
    end
  end

  private

  def rating_params

    params.require(:rating).permit(:book_id, :stars, :user_id)

  end

My book.rb model:

  def avg_rating
    average_rating = 0.0
    count = 0
    ratings.each do |rating|
      average_rating += rating.stars
      count += 1
    end

    if count != 0
      (average_rating / count)
    else
      count
    end
  end

my rating.rb model:

class Rating < ActiveRecord::Base
    belongs_to :book
    belongs_to :user
    attr_accessor :stars
end

anyone has a clue - why this doesn't work?

like image 718
Andrei Cirnici Avatar asked Feb 04 '26 23:02

Andrei Cirnici


1 Answers

At least one of your ratings' stars attribute returns nil. So when you call average_rating += rating.stars, which is equivalent to average_rating = average_rating + nil, you get an error. If nil value in this field means 0, you should probably have:

average_rating += rating.stars || 0

If nil value is undesirable in this field, you should validate it in Rating model:

validates_presence_of :stars

Also, since stars is a field in your ratings table, you don't need attr_accessor :stars in Rating model.

like image 109
Marek Lipka Avatar answered Feb 06 '26 12:02

Marek Lipka



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!