TypeError(nil不能强制转换为Float):

时间:2014-10-31 12:42:20

标签: ruby-on-rails ruby activerecord

我试图实施评级系统。完成this tutorial

当我尝试给出评分时,我一直收到此错误:

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'

我的show.html.erb视图:

<% 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 %>

我的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

我的book.rb模型:

  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

我的rating.rb模型:

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

任何人都有线索 - 为什么这不起作用?

1 个答案:

答案 0 :(得分:0)

至少有一个评分“stars”属性返回nil。因此,当您拨打相当于average_rating += rating.stars的{​​{1}}时,您会收到错误消息。如果此字段中的average_rating = average_rating + nil值表示nil,则您可能应该:

0

如果此字段中不需要average_rating += rating.stars || 0 值,则应在nil模型中对其进行验证:

Rating

此外,由于validates_presence_of :stars stars表中的字段,因此ratings模型中不需要attr_accessor :stars