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.
精彩评论