开发者

Why is my rank_sum database column still nil?

So I have these two methods in my Video model. The first one takes the parameter store and does some funky math to it to return rounded_num. The second method should be setting rank_sum in the database to the value of rounded_num by passing the value of vote_sum to the rank_sum method. Here are the methods:

def rank_sum(score)
  order = Math.log10(([score.abs,1].max))

  if score > 0
    sign = 1
  elsif score < 0
    sign = -1
  else
    sign = 0
  end

  seconds = self.created_at - DateTime.new(1970,1,1)
  long_num = order + sign * seconds / 45000
  return rounded_num = (long_num * 10**7).round.to_f / (10**7)
end

def update_rank_sum
  new_rank = rank_sum(self.vote_sum)
  video.update_attributes!(:rank_sum => new_rank)
end

However, rank_sum is not being set. The value for each video's rank_sum is still nil.开发者_运维问答 How do I fix this?


Since your rank_sum method doesn't directly interact with an instance of the Video model (e.g. one specific video) and instead simply does some calculation, I would make it a class method. This also makes it so that your method isn't overwriting Active Record's own rank_sum method, which it created based on the columns in your database.

Changing some of the names to be more descriptive and cleaning up the return statement in your first method, I would try something like this:

class Video < ActiveRecord::Base
  before_update :update_rank_sum

  def self.calculate_rank_sum(score, created_at)
    order = Math.log10(([score.abs,1].max))

    if score > 0
      sign = 1
    elsif score < 0
      sign = -1
    else
      sign = 0
    end

    seconds = created_at - DateTime.new(1970,1,1)
    long_num = order + sign * seconds / 45000
    (long_num * 10**7).round.to_f / (10**7)
  end

  def update_rank_sum
    self.rank_sum = Video.calculate_rank_sum(self.vote_sum, self.created_at)
  end
end

This will recalculate the rank_sum column every time the record is saved. If you only want to recalculate it if a certain field was changed, you can implement that logic in your update_rank_sum callback. For example, to only calculate a new rank_sum if the vote_sum has been changed:

def update_rank_sum
  if self.vote_sum_changed?
    self.rank_sum = Video.calculate_rank_sum(self.vote_sum, self.created_at)
  end
  true
end

You can replace vote_sum in vote_sum_changed? with whatever column you want to check.

[Edit] You may need to return a non false or nil value in the callback to make sure the record still saves (if you return false from a before_ callback it cancels the save). I've updated the last code block.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜