working quickvote support created
author<mako@atdot.cc> <>
Thu, 12 Oct 2006 01:42:18 +0000 (21:42 -0400)
committer<mako@atdot.cc> <>
Thu, 12 Oct 2006 01:42:18 +0000 (21:42 -0400)
22 files changed:
app/controllers/quickvote_controller.rb [new file with mode: 0644]
app/controllers/site_controller.rb
app/controllers/voter_controller.rb
app/helpers/quickvote_helper.rb [new file with mode: 0644]
app/models/quick_voter.rb
app/models/vote.rb
app/models/voter.rb
app/views/layouts/vb.rhtml
app/views/quickvote/_result.rhtml [new file with mode: 0644]
app/views/quickvote/create.rhtml [moved from app/views/site/create_quickvote.rhtml with 96% similarity]
app/views/quickvote/index.rhtml [new file with mode: 0644]
app/views/quickvote/results.rhtml [new file with mode: 0644]
app/views/quickvote/success.rhtml [moved from app/views/site/success_quickvote.rhtml with 86% similarity]
app/views/quickvote/thanks.rhtml [new file with mode: 0644]
app/views/voter/_vote.rhtml
app/views/voter/full_vote.rhtml
app/views/voter/quickvote.rhtml [deleted file]
config/routes.rb
lib/rubyvote/condorcet.rb
lib/rubyvote/election.rb
public/stylesheets/vb.css
test/functional/quickvote_controller_test.rb [new file with mode: 0644]

diff --git a/app/controllers/quickvote_controller.rb b/app/controllers/quickvote_controller.rb
new file mode 100644 (file)
index 0000000..c3510f6
--- /dev/null
@@ -0,0 +1,78 @@
+class QuickvoteController < ApplicationController
+  layout 'vb'
+  model :quick_voter
+  model :vote
+  model :election
+
+  def index
+    @election = QuickVote.find_all(["name = ?", params[:votename]])[0]
+    
+    @voter = QuickVoter.find_all(["session_id = ? and election_id = ?",
+                                  session.session_id, @election.id])[0]
+    unless @voter 
+      @voter = QuickVoter.new
+      @voter.election = Election.find_all( [ "name = ?", params[:votename] ] )[0]
+    end
+  end
+
+  def create
+    if params[:quickvote] 
+      @quickvote = QuickVote.new(params[:quickvote])
+      if @quickvote.reviewed? and @quickvote.save
+          @quickvote = @quickvote.reload
+         render :action => 'success'
+      end 
+    end
+  end
+
+  def change
+    voter = QuickVoter.find_all(["session_id = ?", session.session_id])[0]
+    voter.destroy
+    redirect_to quickvote_url( :votename => params[:votename] )
+  end
+
+  def confirm
+    election = QuickVote.find_all(["name = ?", params[:votename]])[0]
+
+    if QuickVoter.find_all(["session_id = ? and election_id = ?", 
+                            session.session_id, election.id])[0]
+      flash[:notice] = "You have already voted!"
+      redirect_to quickvote_url( :votename => params[:votename] )
+    else
+      @voter = QuickVoter.new()
+      @voter.election = election
+      @voter.session_id = session.session_id
+      @voter.save
+      @voter.reload
+        
+      @voter.vote = Vote.new
+      @voter.vote.votestring = params[:vote][:votestring]
+      @voter.vote.confirm!
+      render :action => 'thanks'
+    end
+  end
+  
+  def results
+    @election = Election.find_all( ["name = ?", params[:votename]] )[0]
+
+    preference_tally = []
+    plurality_tally = []
+    approval_tally = []
+    @election.voters.each do |voter|
+      plurality_tally << voter.vote.rankings.sort[0].candidate.id
+      approval_tally << voter.vote.rankings.sort[0..1].collect {|ranking| ranking.candidate.id}
+      preference_tally << voter.vote.rankings.sort.collect {|ranking| ranking.candidate.id}
+    end
+    @plurality_result = PluralityVote.new(plurality_tally).result
+    @approval_result = ApprovalVote.new(approval_tally).result
+    @condorcet_result = CloneproofSSDVote.new(preference_tally).result
+    @ssd_result = PureCondorcetVote.new(preference_tally).result
+    @borda_result = BordaVote.new(preference_tally).result
+    @runoff_result = InstantRunoffVote.new(preference_tally).result
+
+    @candidates = {} 
+    @election.candidates.each {|c| @candidates[c.id] = c}
+  end
+
+end
index f4bae4287126e05488dbd76af1d11e2114ecdb33..41eb136a3758256cd066c32cb885ba2259aed2eb 100644 (file)
@@ -11,14 +11,4 @@ class SiteController < ApplicationController
     end
   end
 
     end
   end
 
-  def create_quickvote
-    if params[:quickvote] 
-      @quickvote = QuickVote.new(params[:quickvote])
-      if @quickvote.reviewed? and @quickvote.save
-          @quickvote = @quickvote.reload
-         render :action => 'success_quickvote'
-      end 
-    end
-  end
-
 end
 end
index d2529f8762416927e7775776ef16ae6f0c6fb6f2..1b00b8b00b664ac46d6e9f15303fecf282c38189 100644 (file)
@@ -30,26 +30,7 @@ class VoterController < ApplicationController
   end
 
   def confirm
   end
 
   def confirm
-    if params[:votename]
-      if Voter.find_all( ["session_id = ?", session.session_id ])[0]
-        flash[:notice] = "You have already voted!"
-       redirect_to quickvote_url( :votename => params[:votename] )
-      else
-        @voter = QuickVoter.new()
-        @voter.election = Election.find_all( [ "name = ?",
-                                              params[:votename] ] )[0]
-        @voter.session_id = session.session_id
-        @voter.save
-        @voter.reload
-        
-        @voter.vote = Vote.new
-        @voter.vote.votestring = params[:vote][:votestring]
-        @voter.vote.save
-       @voter.vote.confirm!
-        render :action => 'thanks'
-      end
-      
-    elsif authenticate
+    if authenticate
       @voter.vote.confirm!
       render :action => 'thanks'
     else
       @voter.vote.confirm!
       render :action => 'thanks'
     else
@@ -57,11 +38,6 @@ class VoterController < ApplicationController
     end
   end
 
     end
   end
 
-  def quickvote
-    @voter = QuickVoter.new
-    @voter.election = Election.find_all( [ "name = ?", params[:votename] ] )[0]
-  end
-
   private
   def authenticate
     password = params[:id]
   private
   def authenticate
     password = params[:id]
diff --git a/app/helpers/quickvote_helper.rb b/app/helpers/quickvote_helper.rb
new file mode 100644 (file)
index 0000000..5ccdc27
--- /dev/null
@@ -0,0 +1,2 @@
+module QuickvoteHelper
+end
index 7b934a33f37b29442999fd894ea7c5aef3d2cf12..1a2daf66f057733ae1a38c65c5ac0331c1ef1ad8 100644 (file)
@@ -1,4 +1,6 @@
 class QuickVoter < Voter
   validates_presence_of :session_id
 class QuickVoter < Voter
   validates_presence_of :session_id
-  validates_uniqueness_of :session_id
+
+  # validates_uniqueness_of :session_id
+  # instead we shoudl validate that it's unique for a given election_id
 end
 end
index 7678f5463900034de67c6ff2dff60c2d281a059c..08dd1e7dd2c393bd2580eee0a02319d468a29265 100644 (file)
@@ -41,6 +41,11 @@ class Vote < ActiveRecord::Base
       self.rankings << ranking
     end
   end
       self.rankings << ranking
     end
   end
+  
+  def destroy
+    self.destroy_rankings
+    super
+  end
 
   def destroy_rankings 
     rankings.each { |ranking| ranking.destroy }
 
   def destroy_rankings 
     rankings.each { |ranking| ranking.destroy }
index 7139b899a725fd6b32de66393f7decc58a5d99c8..44efee6e1aa7a0e7b49391955202e82d91e195b9 100644 (file)
@@ -2,6 +2,11 @@ class Voter < ActiveRecord::Base
   belongs_to :election
   has_one :vote
 
   belongs_to :election
   has_one :vote
 
+  def destroy
+    vote.destroy if vote
+    super
+  end
+
 end
 
 
 end
 
 
index 3e4f8bdffcff360a0f2dd62e73379d982decfa6f..71003b502d2927ca8b3e7696487bd3afbafec576 100644 (file)
@@ -40,8 +40,9 @@
           <%= @content_for_layout %>
         </div>
 
           <%= @content_for_layout %>
         </div>
 
-       <hr />
-        <div id="footer">Copyleft 2006 |
+        <div id="footer">
+          <hr />
+         Copyleft 2006 |
          <%= link_to "MIT Media Lab", "http://www.media.mit.edu" %> and
          <a href="http://mako.cc">Benjamin Mako Hill</a>
        </div>
          <%= link_to "MIT Media Lab", "http://www.media.mit.edu" %> and
          <a href="http://mako.cc">Benjamin Mako Hill</a>
        </div>
diff --git a/app/views/quickvote/_result.rhtml b/app/views/quickvote/_result.rhtml
new file mode 100644 (file)
index 0000000..a326459
--- /dev/null
@@ -0,0 +1,10 @@
+<% %>
+<% if result.winner? and result.winners.length == 1%>
+  <p><em>The winner is:
+     <strong><%= @candidates[result.winner].name %></strong></em></p>
+<% elsif result.winner? and result.winners.length > 1 %>
+  <p><em>There was a tie. The winners are: <strong><%=
+  result.winners.collect {|w| @candidates[w]}.join(", ") %></strong></em></p>
+<% else %>
+  <p><em>There is no winner using this method. </em></strong></p>
+<% end %>
similarity index 96%
rename from app/views/site/create_quickvote.rhtml
rename to app/views/quickvote/create.rhtml
index 78addaa0c6a6407a85b9745f4c080a7950135212..7074218ecd17e5a336b9b4cd9195986a2d84f837 100644 (file)
@@ -15,7 +15,7 @@ the election submitted include:</p>
 
 <% end %>
 
 
 <% end %>
 
-<%= form_tag :action => 'create_quickvote' %>
+<%= form_tag :action => 'create' %>
 <!--[form:election]-->
 
 <p><label for="quickvote_name">Vote Name<br />
 <!--[form:election]-->
 
 <p><label for="quickvote_name">Vote Name<br />
diff --git a/app/views/quickvote/index.rhtml b/app/views/quickvote/index.rhtml
new file mode 100644 (file)
index 0000000..2c5bcd1
--- /dev/null
@@ -0,0 +1,18 @@
+<% %>
+<h1>QuickVote: <em><%= @voter.election.name %></em></h1>
+
+<p><strong>Description:</strong></p>
+<blockquote><%= @voter.election.description %></blockquote>
+
+<h2>Vote in Election</h2>
+<% if @voter.session_id %>
+  <p>You have already voted. You can:</p>
+  
+  <ul>
+    <li><%= link_to "Change your vote.", quickaction_url( :votename => @voter.election.name, :action => 'change' ) %></li>
+
+    <li><%= link_to "View election results.", quickaction_url( :votename => @voter.election.name, :action => 'results' ) %></li>
+  </ul>
+<% else %>
+  <%= render_partial 'voter/vote' %>
+<% end %>
diff --git a/app/views/quickvote/results.rhtml b/app/views/quickvote/results.rhtml
new file mode 100644 (file)
index 0000000..ad71fa6
--- /dev/null
@@ -0,0 +1,36 @@
+<% %>
+
+<h1><em><%= @election.name %></em> Results</h1>
+
+<p>Total Votes: <strong><%= @election.voters.length %></strong></p>
+<div class="mainresultbox">
+<h2>Condorcet (w/ Cloneproof SSD) Results</h2>
+<%= render :partial => 'result', :object => @ssd_result %>
+</div>
+
+<div class="resultbox">
+<h2>Plurality Results</h2>
+<%= render :partial => 'result', :object => @plurality_result %>
+</div>
+
+<div class="resultbox">
+<h2>Approval Result</h2>
+<p><font size="-1">(Assuming top two choices are "approved.")</font></p>
+<%= render :partial => 'result', :object => @approval_result %>
+</div>
+
+<div class="resultbox">
+<h2>Simple Condorcet Results</h2>
+<%= render :partial => 'result', :object => @condorcet_result %>
+</div>
+
+<div class="resultbox">
+<h2>Borda Count Results</h2>
+<%= render :partial => 'result', :object => @borda_result %>
+</div>
+
+<div class="resultbox">
+<h2>Instant Runoff (IRV) Results</h2>
+<%= render :partial => 'result', :object => @runoff_result %>
+</div>
+</div>
similarity index 86%
rename from app/views/site/success_quickvote.rhtml
rename to app/views/quickvote/success.rhtml
index 299edacdfc54cbc8745c5b7f13ad06271c4f0f48..982fd1236484a0f4e9bf8cadd3570b9b4ec87608 100644 (file)
@@ -1,8 +1,6 @@
 <% %>
 
 <% %>
 
-<p>Vote Created</p>
-
-<p>You have successfully created a QuickVote.</p>
+<h2>Vote Created</h2:>
 
 <p>QuickVotes are open to the public but are not publicly listed on the
 HyperChad site. Voters do not need to log in or authenticate to
 
 <p>QuickVotes are open to the public but are not publicly listed on the
 HyperChad site. Voters do not need to log in or authenticate to
diff --git a/app/views/quickvote/thanks.rhtml b/app/views/quickvote/thanks.rhtml
new file mode 100644 (file)
index 0000000..794f412
--- /dev/null
@@ -0,0 +1,23 @@
+<% %>
+
+<p>Your vote has been recorded with the following ranked
+preferences:</p>
+
+<ol>
+  <% for rank in @voter.vote.rankings.sort %>
+    <li><%= rank.candidate.name %> </li>
+  <% end %>
+</ol>
+
+<p>Thanks you voting! You can:</p>
+
+<ul>
+  <li><%= link_to "Change your vote.", quickaction_url( :votename => @voter.election.name, :action => 'change' ) %></li>
+
+  <li><%= link_to "View election results.", quickaction_url( :votename => @voter.election.name, :action => 'results' ) %></li>
+</ul>
+
+
+
+
+
index e74202104929f63f7acabe19b89e12714ea72465..b9a2688c9c001d8b59f26a03051cd9cb7706c081 100644 (file)
@@ -1,37 +1,22 @@
 <% %>
 
 <% %>
 
-<% if @voter.election.quickvote? %>
-  <h1>QuickVote: <em><%= @voter.election.name %></em></h1>
-  <p><strong>Description:</strong></p>
-  <blockquote><%= @voter.election.description %></blockquote>
-<% else %>
-  <p><strong>Election:</strong> <%= @voter.election.name %></p>
-  <p><strong>Voter:</strong> <%= @voter.email %></p>
-  <p><strong>Description:</strong></p>
-  <blockquote><%= @voter.election.description %></blockquote>
-<% end %>
-
-<p><strong>Candidates:</strong></p>
+<p><strong>Candidates or choices:</strong></p>
 <ol>
 <% for candidate in @voter.election.candidates.sort %>
   <li><%= candidate.name %></li>
 <% end %>
 </ol>
 
 <ol>
 <% for candidate in @voter.election.candidates.sort %>
   <li><%= candidate.name %></li>
 <% end %>
 </ol>
 
-<hr />
-
-<h2>Place Your Vote Here</h2>
-
-<p>Rank each candidate in order of more preferred to least
-preferred. (e.g., 123 or 321 or 213, etc.)</p>
+<p>In the box below, list each choice in order of most preferred to
+least preferred.  <em>(For example, 123 or 321 or 213, etc.)</em></p>
 
 <% if @voter.election.quickvote? %>
 
 <% if @voter.election.quickvote? %>
-  <%= form_tag quickconfirm_url( :votename => @voter.election.name ) %>
+  <%= form_tag quickaction_url( :votename => @voter.election.name, :action => 'confirm') %>
 <% else %>
   <%= form_tag :action => 'review', :id => @voter.password %>
 <% end %>
 
 <%= text_field :vote, :votestring -%>
 <% else %>
   <%= form_tag :action => 'review', :id => @voter.password %>
 <% end %>
 
 <%= text_field :vote, :votestring -%>
-<%= submit_tag "Submit!" %>
+<%= submit_tag "Vote!" %>
 <%= end_form_tag %>
 
 <%= end_form_tag %>
 
index 599308f795d30830327d9dfbf4a787e42023d344..2f1fc22a71f924acceeb9a5a01ce8cd1d0b9ea59 100644 (file)
@@ -1,5 +1,10 @@
 <% %>
 
 <% %>
 
+<p><strong>Election:</strong> <%= @voter.election.name %></p>
+<p><strong>Voter:</strong> <%= @voter.email %></p>
+<p><strong>Description:</strong></p>
+<blockquote><%= @voter.election.description %></blockquote>
+
 <%= render_partial 'vote' %>
 
 
 <%= render_partial 'vote' %>
 
 
diff --git a/app/views/voter/quickvote.rhtml b/app/views/voter/quickvote.rhtml
deleted file mode 100644 (file)
index 3cb2eda..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-<% %>
-<%= render_partial 'vote' %>
index af9820fdab90256d33fe6a0b7b17ed8ac4023b52..d1092a0bbe4511b6958c915b078785085e563dea 100644 (file)
@@ -12,18 +12,18 @@ ActionController::Routing::Routes.draw do |map|
   # You can have the root of your site routed by hooking up '' 
   # -- just remember to delete public/index.html.
   map.connect '', :controller => "site"
   # You can have the root of your site routed by hooking up '' 
   # -- just remember to delete public/index.html.
   map.connect '', :controller => "site"
-
   map.connect 'quickvote/create',
   map.connect 'quickvote/create',
-             :controller => 'site',
-             :action => 'create_quickvote'
-             
-  map.quickconfirm 'quickvote/:votename/confirm',
-              :controller => 'voter',
-             :action => 'confirm'
+              :controller => 'quickvote',
+             :action => 'create'
+
+  map.quickaction 'quickvote/:votename/:action',
+                  :controller => 'quickvote',
+                 :requirements => { :action => /(change|confirm|results)/ }
 
   map.quickvote 'quickvote/:votename',
 
   map.quickvote 'quickvote/:votename',
-                :controller => 'voter',
-               :action => 'quickvote'
+                :controller => 'quickvote',
+               :action => 'index'
 
   # Allow downloading Web Service WSDL as a file with an extension
   # instead of a file named 'wsdl'
 
   # Allow downloading Web Service WSDL as a file with an extension
   # instead of a file named 'wsdl'
index 616de48784f741de7aff1c1b2a99eb229548a333..95663d4e4dbee63bbc4a97fea93c90c3791ef3bf 100644 (file)
@@ -142,7 +142,7 @@ class PureCondorcetResult < CondorcetResult
         victors[candidate].length == @election.candidates.length - 1
     end
 
         victors[candidate].length == @election.candidates.length - 1
     end
 
-    @winners << winners if winners.length == 1
+    @winners = winners if winners.length == 1
   end
 end
 
   end
 end
 
index 7fd8396c046d9b71fd09c75e2f35866ddbe5cf97..fc61840a8aec6172d498345b2b387f79bf4795ce 100644 (file)
@@ -70,7 +70,7 @@ class PluralityVote < ElectionVote
   
   protected
   def verify_vote(vote=nil)
   
   protected
   def verify_vote(vote=nil)
-    vote.instance_of?( String )
+    vote ? true : false
   end
 
   def tally_vote(candidate)
   end
 
   def tally_vote(candidate)
index 9f0d7c82d6548ce3500a6bb30f91276ec23ff4dd..e6940698d22a755868476fb5624bb5ef7827b1d4 100644 (file)
@@ -92,7 +92,8 @@ a:active { color: #FFFFFF; text-decoration: none; background: #0259C4; }
 
 #footer { text-align: center;
           font-size: 12px;
 
 #footer { text-align: center;
           font-size: 12px;
-          color: #464646; }
+          color: #464646;
+         clear: both;}
 
 #footer a { font-weight: normal; }
        
 
 #footer a { font-weight: normal; }
        
@@ -107,3 +108,27 @@ a:active { color: #FFFFFF; text-decoration: none; background: #0259C4; }
 .fieldWithErrors input, .fieldWithErrors select {
     background-color: #ffdfdf;
 }
 .fieldWithErrors input, .fieldWithErrors select {
     background-color: #ffdfdf;
 }
+
+.mainresultbox {
+    width: 100%;
+    padding: 7px;
+    margin-right: 10px;
+    margin-bottom: 10px;
+    border-style: dotted;
+    border-width: 1px;
+}
+
+.mainresultbox h1 {
+    text-align: center;
+}
+.resultbox {
+    width:47%;
+    float: left;
+    padding: 7px;
+    margin-right: 10px;
+    margin-bottom: 10px;
+    border-style: dotted;
+    border-width: 1px;
+}
+
+
diff --git a/test/functional/quickvote_controller_test.rb b/test/functional/quickvote_controller_test.rb
new file mode 100644 (file)
index 0000000..d0b37d9
--- /dev/null
@@ -0,0 +1,18 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require 'quickvote_controller'
+
+# Re-raise errors caught by the controller.
+class QuickvoteController; def rescue_action(e) raise e end; end
+
+class QuickvoteControllerTest < Test::Unit::TestCase
+  def setup
+    @controller = QuickvoteController.new
+    @request    = ActionController::TestRequest.new
+    @response   = ActionController::TestResponse.new
+  end
+
+  # Replace this with your real tests.
+  def test_truth
+    assert true
+  end
+end

Benjamin Mako Hill || Want to submit a patch?