2011-02-24 1 views
3

내 모델 협회입니다논리와 코드 도움

  • 사용자는
  • 수상 사용자에 속하는 많은 수상 경력을 가지고
  • 수상은
  • 수상
상에 속하는 많은 수상 경력을 가지고

4 개의 상금 (기록으로 캡처 됨)이 있다고 가정 해 보겠습니다.

,210
  • 포니
  • 장난감
  • AwesomeStatus 사용자가 이러한 경품 중 하나 이상을 수여 할 수있다

매일. 그러나 사용자는 하루에 한 번씩 각 상품을 수령 할 수 있습니다. 사용자가 AwesomeStatus를 획득 한 경우, 예를 들어, 사용자 및 상품에 fk가있는 어워드 테이블에 레코드가 추가됩니다. 분명히, 사용자가 하루 동안 AwesomeStatus에서 우승하지 않으면 레코드가 추가되지 않습니다.

하루가 끝날 때 (자정 전까지), AwesomeStatus를 분실 한 사용자 목록을 반환하고 싶습니다. (물론, AwesomeStatus를 잃어 버리려면 그 전날을 보내야했다.) 불행히도, 내 경우에는 관찰자가 작동하지 않을 것이며 스크립트에 의존해야한다고 생각한다. 어쨌든 AwesomeStatus를 잃은 사용자를 결정하는 방법에 대해 어떻게 생각하십니까? 참고 : 시간대 (이 경우 하루)에 지나치게 의존하는 솔루션을 만들지 마십시오. 나는 사용자가 상금을 받고 (그리고 상실 할 수있는) 모든 기간에 몇 번이나 유연성을 유지하려고합니다.

+0

좋은 질문 .... – Andrew

답변

2

은 아마 이런 짓을 할 것이다 :

클래스 상 또한 상품이 수여 된 날을 포함하는 열 awarded_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

나는 주어진 시간 기간 (일, 주, 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 
0

그냥 updated_at 사용하거나, 위의 제안 같은 awarded_at를 추가하고 사용 다음과 같이하십시오 :

scope :awarded, proc {|date| where(["updated_at <= ?", date])} 

보너스 모델.상에 'lasts_for'를 던져과 비교할 당신이 동적하려면

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)} 

는 등, 어딘가 표시 단순히 '활성'을 설정하는 유지 보수 cronjob에 쓰기 : 어쩌면, 이런 식으로 인쇄하기 boolean on the Award는 협회를 삭제하는 대신 false로 설정합니다.