开发者

What is the best approach to build a voting system for an item held in a queue, which will expire? Background task required?

I am building an app in Rails 3 (and Ruby 1.9.2) which takes submissions from multiple users. The app closes the submissions window after X amount of time. Then, everyone is to vote (thumbs up/thumbs down) on the submissions. After Y amount of time, the one with the most votes "wins", and the process repeats.

I'm a noob, but I have the basic models built housing the submissions, RESTful routes, user a开发者_开发技巧uthentication with Devise, etc. But now my experience has run out and I'm not quite sure what the best approach is to building the "holding" system that will countdown the time until no votes are accepted and a winner is chosen. I think I will create a vote object, so that each submission can have many votes. But it seems like maybe something is needed in the background to wake up after the timer runs down for voting and say, "okay, this voting period has ended, now move the winner into the DB and start taking new submissions before the next voting round". Is this right or can it be simpler than this?

Any suggestions on how I should think about this concept?

Thanks!!


So you've got some kind of Ballot model. Ballot has many Submissions, submission has many Votes. There's a WinningSubmission model as well. Ballot has_one WinningSubmission.

I think it's probably easiest to have Ballot contain the timestamps for X and Y.

If you don't want to have some cron job that polls for completed-voted-ballots, you can run a general before_filter in ApplicationController (or, preferably, create a blank controller just for this filter, and have the other controllers that manage the voting inherit from it) that checks on each request to see if any ballots are closed, but also have no winners; then calculate the winners on those, before continuing with the request. It's just like a job worker, except it's within the webserver, so it adds some small amount of response delay.

As far as the Controller/View architecture of how submissions and votes are created, I'd probably have thrice nested controllers:

resources :ballots do       # These blocks may need to pass in their object 
                            # depending on your rails version.

  resources :submissions do 
    # POST to ballot_submissions_path(@ballot) creates subs's.

    resources :votes # POST to ballot_submission_votes_path(@b, @s) creates votes.
  end 
end 

I'd have to know more about your interaction design to help with any view/ajax level interaction beyond the 'create' actions, but I'm guessing you'd either go with a one-page index style design at the ballot-submission level, or with a series of views, one for each state a ballot can be in. These would probably get sprinkled across the #index actions of the various controllers for simplicity's sake.

As above, if you didn't want to use a cronjob or job worker, I'd have BallotsController, SubmissionsController, and VotesController all < BallotCompleterController like so:

class VotesController < BallotCompleterController
#your vote handling actions would go here.
end

class BallotCompleterController < ApplicationController
  before_filter :complete_unfinished_ballots
  protected
  def complete_unfinished_ballots
     Ballot.expectant.calculate_all!
  end
  #and that's all that's in here
end

class Ballot < ActiveRecord::Base
  #...has_many etc's
  named_scope :expectant, lambda{ 
   {:select => "ballots.*",
    :conditions => ['votes_until < ? and winning_submissions.id is null', Time.current],
    :joins => 'left outer join winning_submissions 
               on winning_submissions.ballot_id = ballots.id', 
    :readonly => false} }

 def self.calculate_all!
   self.each(&:'calculate_winning_submission!') 
 end

 def calculate_winning_submission!
   #calc and save the winning_submission for this ballot
 end

end


I don't think you need background tasks -- instead, just have an AJAX poller that refreshes the page and display the voting form when it's ready.

So your submission only accepts votes during the valid time (specifically the votes validates that Time.now is between the submission start/end time). That'll keep your data intact.

Then on your HTML, just start by having your page refresh every minute, and then get it to only refresh when the valid time starts (and refresh again when it ends).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜