我正试图建立一个评级系统。我最近升级了我的迁移文件。
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方法,它可能在模型中记录了该属性。
我认为我非常接近,但看起来我需要帮助。任何建议表示赞赏。提前谢谢。
答案 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] || 0
和if rating.nil? || rating == 0
。这变得复杂,因为您期望nil
或0
。克服这种复杂性的最简单方法是告诉数据库不允许空值,并设置一些默认值(在您的情况下为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整数。我使用类型转换将数字转换为十进制,但值本身存储为整数。
更改迁移解决了这个问题。