我有三个模型:
- 课程用户
- CourseCompletion
除了标题和内容,每门课程也有一个积分值。当用户完成一门课程时,他们将获得该课程的积分值,该积分值将添加到他们的total_points
中。courseccompletion简单地跟踪哪个用户完成了哪些课程(列user_id
, course_id
和completion_date
)。
此数据模型的一个缺点是,如果管理用户在用户完成课程后编辑课程的积分值,则不会更新该用户的积分。我需要一种追溯的方法。例如,如果用户完成一门课程并获得10分,然后管理员将该课程更改为20分,那么用户最终应该获得20分。我以前没有做过这种事情——最好的方法是什么?
我目前的计划是双重的。在第一部分中,我对Course和courseccompletion模型进行了更改:
- 在courseccompletion中添加一个
points_earned
列,记录用户完成该任务所获得的积分。 - 添加
points_recently_changed
列到Course。如果某个球场的积分在任何时候都有更新,那么将该球场的这一列设置为true。(见我的相关问题)
在第二部分中,脚本或任务(?)每天运行一次,并执行以下操作:
- 获取
points_recently_changed
= true的所有课程 - 查找这些课程的所有完成情况
- 计算航向差。积分和course_completion.points_earned
- 相应更新相应用户积分总数
- 改变方向。points_recently_updated返回false
这种方法有什么明显的问题吗,或者有"Rails方式"做这样的事情吗?
为什么不使用ActiveRecord:: calculation来获取所有相关课程的积分之和,并将其存储在列中。每当管理员更改课程点数时,更新该列。
您可以使用ActiveRecord::Dirty来跟踪点的变化
http://api.rubyonrails.org/classes/ActiveModel/Dirty.html和计算点使用计算:
http://api.rubyonrails.org/classes/ActiveRecord/Calculations.html作为可能的解决方案:
class Course < ActiveRecord::Base
before_save :update_user_points
def update_user_points
User.all.each {|user| user.update_points } if self.points_changed?
end
end
class User < ActiveRecord::Base
def update_points
self.points = self.courses.sum(:points)
end
end
建议:
我不喜欢在数据库中保存点,因为它是一个变量。我建议您在每次用户登录时进行计算,并将其作为带过期日期的缓存数。所以每天都要重新计算
我尝试了乔治的建议,但并不满意。我最终采用了类似的方法,即在登录过程中重新计算用户的分数。
User.rb
def recalculate_points
new_course_points = self.course_completion_courses.sum(:worth)
self.update_attribute(:points, self.course_completion_courses.sum(:worth))
self.save
end
session_helper.rb
def sign_in(user)
...
current_user.recalculate_points
end
点仍然存储在User表中—简单地缓存它们不起作用,因为我要做一些报告,需要将这些信息保存在数据库中。