以下是我的模特和协会:
让我们假装有四个奖品(作为记录捕获):
用户每天都可以获得一个或多个奖品。但用户每天只能获得一次奖品。如果用户赢得AwesomeStatus,例如,将一条记录添加到奖励表中,其中fk为User和Prize。显然,如果用户当天没有赢得AwesomeStatus,则不会添加任何记录。
在一天结束时(在午夜之前,让我们说),我想返回丢失了他们的AwesomeStatus的用户列表。 (当然,要失去你的AwesomeStatus,你必须在前一天。)不幸的是,在我的情况下,我不认为观察者会工作,并且将不得不依赖脚本。无论如何,你将如何确定哪些用户丢失了他们的AwesomeStatus?注意:不要让你的解决方案过度依赖于一段时间 - 在这种情况下是一天。我想保持每个时期用户有多少次获得奖金的灵活性(并且也失去它)。
答案 0 :(得分:2)
我可能会这样做:
班级奖励也应该有一列award_at,其中包含奖励的日期。因此,当创建奖项时,可以这样做:
# This will make sure that no award will be created if it already exists for the current date
@user.awards.find_or_create_by_prize_id_and_awarded_at(@prize.id, Time.now.strftime("%Y-%m-%d"))
然后我们可以设置一个范围来为所有用户加载一个将于今天到期的奖励,并且没有奖励所提供的奖品。
# user.rb
scope :are_losing_award, lambda { |prize_id, expires_after|
joins("INNER JOIN awards AS expired_awards ON users.id = expired_awards.user_id AND expired_awards.awarded_at = '#{(Time.now - expires_after.days).strftime("%Y-%m-%d")}'
LEFT OUTER JOIN awards AS active_awards ON users.id = active_awards.user_id AND active_awards.awarded_at > '(Time.now - expires_after.days).strftime("%Y-%m-%d")}' AND active_awards.prize_id = #{prize_id}").
where("expired_awards.prize_id = ? AND active_awards.id IS NULL", prize_id)
}
那么我们可以这样称呼它:
# Give me all users who got the prize three days ago and has not gotten it again since
User.are_losing_award(@prize.id, 3)
可能有一些方法可以更好地使用ARel查询或其他东西来编写范围,我还不是那么专家,但这种方式应该适用于那时:)
答案 1 :(得分:0)
我会在奖励中添加一个整数“时间段”字段,代表给定的时间段(日,周,5小时,无论你想要什么)。
现在,您可以在奖励表中搜索奖励状态为t-1但不是t的用户:
SELECT prev.user_id
FROM awards prev
OUTER JOIN awards current ON prev.user_id = current.user_id
AND prev.prize_id = current.prize_id
AND current.time_period = 1000
WHERE prev.prize_id = 1
AND current.prize_id IS NULL
AND prev.time_period = 999
答案 2 :(得分:0)
只需使用updated_at,或添加上述建议的award_at,并按照以下方式使用:
scope :awarded, proc {|date| where(["updated_at <= ?", date])}
在您的奖励模型中。像这样打印,也许:
awesome_status = Prize.find_by_name('AwesomeStatus')
p "Users who do not have AwesomeStatus anymore:"
User.all.each {|user| p user.username if user.awards.awarded(1.day.ago).collect(&:id).include?(awesome_status)}
如果你想要它是动态的,在某处显示,等等。将'lasts_for'扔进Prize并与之比较,然后简单地编写一个维护cronjob,将Award上的'active'布尔值设置为false而不是删除关联。