Справка по логике и коду - PullRequest
       42

Справка по логике и коду

3 голосов
/ 24 февраля 2011

Вот мои модели и ассоциации:

  • У пользователя много наград
  • Награда принадлежит пользователю
  • У премии много наград
  • Наградапринадлежит Призу

Давайте представим, что есть четыре Приза (захваченные как записи):

  • Пони
  • Игрушка
  • Гам
  • AwesomeStatus

Каждый день Пользователь может получить один или несколько из этих Призов.Но Пользователь может получить каждый Приз только один раз в день.Если пользователь выигрывает AwesomeStatus, например, запись добавляется в таблицу наград с fk для пользователя и премии.Очевидно, что если пользователь не выиграл AwesomeStatus за день, запись не будет добавлена.

В конце дня (скажем, до полуночи) я хочу вернуть список пользователей, которые потерялиих AwesomeStatus.(Конечно, чтобы потерять свой AwesomeStatus, вы должны были иметь его накануне.) К сожалению, в моем случае, я не думаю, что наблюдатели будут работать и должны будут полагаться на сценарий.В любом случае, как бы вы определили, кто из пользователей потерял свой AwesomeStatus?Примечание: не делайте ваше решение чрезмерно зависимым от периода времени - в данном случае дня.Я хочу сохранить гибкость в том, сколько раз за любой период у пользователей есть возможность выиграть приз (а также потерять его).

Ответы [ 3 ]

2 голосов
/ 24 февраля 2011

Я бы, наверное, сделал что-то вроде этого:

Награда класса также должна иметь столбец 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 или что-то в этом роде, я пока не эксперт, но этот способ должен работать до тех пор:)

0 голосов
/ 12 марта 2011

Просто используйте updated_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 значение false вместо удаления ассоциации.

0 голосов
/ 07 марта 2011

Я бы добавил целое поле «период времени» к наградам, которое обозначает определенный период времени (день, неделя, 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
...