当我的其他属性有值时,为什么我的[:Rating]属性为零?

时间:2014-08-21 17:22:29

标签: ruby-on-rails ruby activerecord attributes null

我正试图建立一个评级系统。我最近升级了我的迁移文件。

class AddRatingsToPictures < ActiveRecord::Migration
  def change
    add_column :pictures, :ratings_count, :integer
    add_column :pictures, :rating_total, :integer
    add_column :pictures, :rating, :integer
  end
end

这是我模型中的代码

def ratings_count
  self[:ratings_count] || 0
end

def ratings_total
  self[:rating_total] || 0
end

def add_rating(rating)
  return if rating.nil? || rating == 0

  self.ratings_count += 1
  self.rating_total += rating.to_i
  self.stars = (self.rating_total.to_f / self.ratings_count)
  self.save
end

def rating
  self[:rating] || 0
  return 0 if self.ratings_count == 0
  (self.rating_total.to_f / self.ratings_count).round(2)
end

以下是我在Rails控制台中尝试过的一些内容

p = Picture.find(1)
p.rating == nil
false
p[:rating] == nil
true

我认为问题出在这个片段中。

def rating
  self[:rating] || 0
  return 0 if self.ratings_count == 0
  (self.rating_total.to_f / self.ratings_count).round(2)
end

如果我在对象上调用 .rating ,则返回正确的评级。如果我在对象上调用[:rating],则返回nil。

我问这个的原因是因为我需要这个用于Active Record Querying,我必须调用实际属性。具体来说,这行代码。

<% Picture.where("rating >= 4.5").order(rating: :desc, title: :asc).each do |picture|  %>

我的评分方法有效,但仅作为方法调用,而不是作为属性。并考虑到:ratings_count和:rating_total都可以工作。

p.ratings_count
=> 2
p[:ratings_count]
=> 2
p.rating_total
=> 9
p[:rating_total]
=> 9

所以看起来我的方法可以为我的模型创建属性。原因可能在于我的add_rating方法。

def add_rating(rating)
  return if rating.nil? || rating == 0

  self.ratings_count += 1
  self.rating_total += rating.to_i
  self.stars = (self.rating_total.to_f / self.ratings_count)
  self.save
end

上面,我调用了save方法,它可能在模型中记录了该属性。

我认为我非常接近,但看起来我需要帮助。任何建议表示赞赏。提前谢谢。

3 个答案:

答案 0 :(得分:1)

这可能无法解决add_rating跳闸问题,但您可以在迁移中设置默认设置,这样它们永远不会为零,您可以简化每种方法的逻辑运算,可以更轻松地跟踪问题

class AddRatingsToPictures < ActiveRecord::Migration
  def change
    add_column :pictures, :ratings_count, :integer, default: 0
    add_column :pictures, :rating_total, :integer, default: 0
    add_column :pictures, :rating, :integer, default: 0
  end
end

答案 1 :(得分:1)

picture[:rating]返回列的实际属性值,因为它在数据库中,因此如果未设置数据库中的值,它将返回nil,即使您已设置在迁移中键入整数。

在您的代码中,有很多条件,例如self[:rating] || 0if rating.nil? || rating == 0。这变得复杂,因为您期望nil0。克服这种复杂性的最简单方法是告诉数据库不允许空值,并设置一些默认值(在您的情况下为0)。你应该像这样进行迁移:

class AddRatingsToPictures < ActiveRecord::Migration
  def change
    add_column :pictures, :ratings_count, :integer, null: false, default: 0
    add_column :pictures, :rating_total, :integer, null: false, default: 0
    add_column :pictures, :rating, :integer, null: false, default: 0
  end
end

现在,您的数据库确保从不在这些列中具有空值,并且如果您不提供默认值,它将负责设置默认值。

现在您也可以减少代码:

def add_rating(rating)
  return if rating.to_i == 0

  self.ratings_count += 1
  self.rating_total += rating.to_i
  self.stars = (rating_total.to_f / ratings_count)
  self.save
end

def rating
  return 0 if ratings_count == 0

  (rating_total.to_f / ratings_count).round(2)
end

现在,查看代码,您将一些属性stars设置为平均评分。实际的rating属性根本没有设置。我没有足够的信息确定,但我假设stars实际上应该rating在这里?那么你得到:

def add_rating(rating)
  return if rating.to_i == 0

  self.ratings_count += 1
  self.rating_total += rating.to_i
  self.rating = (rating_total.to_f / ratings_count)
  self.save
end

答案 2 :(得分:0)

好吧,我发现了问题。这是我将评级存储为整数而不是小数。

add_column :pictures, :rating, :integer, default: 0, null: false

应该是

add_column :pictures, :rating, :decimal, default: 0, null: false

我的方法要求我将ratings_total除以ratings_count整数。我使用类型转换将数字转换为十进制,但值本身存储为整数。

更改迁移解决了这个问题。