【问题标题】:Why is my [:Rating] attribute nil when my other attributes have values?当我的其他属性有值时,为什么我的 [:Rating] 属性为零?
【发布时间】:2014-08-21 17:22:28
【问题描述】:

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

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

我认为问题在于这个sn-p。

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方法,大概记录了模型中的属性。

我想我已经很接近了,但看起来我需要帮助。任何建议表示赞赏。提前致谢。

【问题讨论】:

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


    【解决方案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
    

    【讨论】:

    • 我认为这不是答案。我的 ratings_count 和 rating_total 属性不是 nil,而且我没有包含 default: 0。不过可能值得一看。
    【解决方案2】:

    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
    

    【讨论】:

    • 这有潜力,不幸的是这条线有问题。 self.rating_total += 评分。这会导致 TypeError: String can't be coerced into fixnum。我知道我们将类型设置为整数,但也许我们需要先将 rating_total 转换为浮点数。我会调查一下。我们还删除了 rating_total 和 ratings_count 方法。
    • 我猜那个参数会是一个字符串。我更新了答案以将其转换为整数。你已经有了这个铸件,我想我有点太急于删除它;)
    • 完美,这解决了我的 nil 问题。但是 [:rating] 仍然设置为 0 而不是计算出来的评分。
    【解决方案3】:

    好的,我找到了问题所在。那是我将评级存储为整数而不是小数。

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

    应该是

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

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

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

    【讨论】:

      猜你喜欢
      • 2016-11-15
      • 2020-05-13
      • 2013-03-13
      • 2015-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多