Created a partial to DRY the aja voting method. Modified the voter class to
author<jlsharps@mit.edu> <>
Wed, 29 Aug 2007 22:06:16 +0000 (18:06 -0400)
committer<jlsharps@mit.edu> <>
Wed, 29 Aug 2007 22:06:16 +0000 (18:06 -0400)
have both a FullVoter and QuickVoter `types`. Also changed the index and review
methods so that they are more error resistant in the face of ajax voting.
Application.rb now includes the sort_candidates method from
quickvote_controller so all election types can use it. Also updated the
election results pages so that they don't throw errors any more. (Show and Hide
details)

20 files changed:
app/controllers/application.rb
app/controllers/election_controller.rb
app/controllers/quickvote_controller.rb
app/controllers/voter_controller.rb
app/models/full_voter.rb
app/models/raw_voter_list.rb
app/models/token.rb
app/models/vote.rb
app/models/voter.rb
app/views/election/_candidate_line.rhtml
app/views/election/_candidate_list.rhtml
app/views/election/_overview_form.rhtml
app/views/site/index.rhtml
app/views/voter/_sortable_vote.rhtml [new file with mode: 0644]
app/views/voter/_vote.rhtml
app/views/voter/full_vote.rhtml
app/views/voter/review.rhtml
app/views/voter_notify/votestart.rhtml
db/create.sql
db/schema.rb

index aeb2204f38ef75015b229032463114d7975330be..5b55d0bc97c1a23c6ef0653dbe04bb987062b009 100644 (file)
@@ -5,6 +5,7 @@ class ApplicationController < ActionController::Base
   include AuthenticatedSystem
   helper :user
   require_dependency "user"
+
   before_filter :add_stylesheets
    
   def initialize
@@ -18,4 +19,14 @@ class ApplicationController < ActionController::Base
     end
   end
 
+  #both election_controller and quickvote_controller need this method
+  def sort_candidates
+    @vote = Vote.find(params[:id])
+
+    @vote.rankings.each do |ranking|
+      ranking.rank = params['rankings-list'].index(ranking.candidate.id.to_s) + 1
+      ranking.save
+    end
+    render :nothing => true
+  end
 end
index 570f1fc3687a4162428555d06829544074d74b93..fa1313cb68cecdd0f06d8c5c8ff14f9004f8ab9c 100644 (file)
@@ -60,8 +60,8 @@ class ElectionController < ApplicationController
 
   def start_election
     @election = Election.find(params[:id])
-    
     @election.voters.each do |voter|
+      voter.vote = Vote.new
       email = VoterNotify.deliver_votestart(voter)
       #render(:text => "<pre>" + email.encoded + "</pre>")
     end
@@ -69,15 +69,6 @@ class ElectionController < ApplicationController
     @election.activate!
     redirect_to :action => 'show', :id => @election.id
   end
-  
-  def change_notices
-    election = Election.find(params[:id])
-    if election.notices == 0
-      election.notices = 1 
-    else
-      election.notices = 0
-    end
-  end
 
   # methods fod display, adding, deleting, and manipulating candidate
   # information for elections
@@ -108,13 +99,13 @@ class ElectionController < ApplicationController
 
   def lessinfo_candidate
     @show_details = false
-    @candidate = Candidate.find( params[:id] )
+    @current_candidate = Candidate.find( params[:id] )
     render :partial => 'candidate_line'
   end
 
   def moreinfo_candidate
     @show_details = true
-    @candidate = Candidate.find( params[:id] )
+    @current_candidate = Candidate.find( params[:id] )
     render :partial => 'candidate_line'
   end
 
@@ -192,7 +183,7 @@ class ElectionController < ApplicationController
     @election.voters. each do |voter|
       if voter.vote and voter.vote.confirmed?
         @voter_list << voter.email
-       @vote_list << voter.vote
+             @vote_list << voter.vote
       end
     end
 
@@ -209,7 +200,7 @@ class ElectionController < ApplicationController
 
       unless incoming_voters.entries.empty?
         incoming_voters.each do |new_voter|
-
+          
           if incoming_voters.email == 0
             new_voter.contacted = 1
                elsif incoming_voters.email == 1
index 1e5b14226b0049a83c3bab7477a75de2ee57bbd5..a5c8065035ef1147d1428831cc09dcd7a067c907 100644 (file)
@@ -160,16 +160,6 @@ class QuickvoteController < ApplicationController
     voter.destroy
     redirect_to quickvote_url( :ident => params[:ident] )
   end
-
-  def sort_candidates
-    @vote = Vote.find(params[:id])
-
-    @vote.rankings.each do |ranking|
-      ranking.rank = params['rankings-list'].index(ranking.candidate.id.to_s) + 1
-      ranking.save
-    end
-    render :nothing => true
-  end
                
   def mapvoters
     @map = GMap.new("map_div_id") 
index f4e0e7e7d782e9d67c13518d15758f616b8c9764..6693b0fa6baa9090cfa6c72b146a240f3d95024e 100644 (file)
@@ -8,22 +8,17 @@ class VoterController < ApplicationController
     password = params[:id]
     password = params[:vote][:password] if params[:vote]
     if @voter = FullVoter.find(:all, :conditions => [ "password = ?", password ] )[0]
-      render :action => 'fullvote'
+      @voter.vote = Vote.new if @voter.vote.nil?
+      @voter.vote.set_defaults! if @voter.vote.rankings.empty?
+      render :action => 'full_vote'
     end
   end
   
   def review
     if authenticate
-      # remove any existing votes and reload
-      if @voter.vote
-        @voter.vote.destroy
-        @voter.reload
-      end
-    
-      @vote = Vote.new
-      @voter.vote = @vote
-      @vote.votestring = params[:vote][:votestring] 
-      @vote.save
+      @voter.vote.time = Time.now
+      @voter.vote.save
+      @voter.reload
     else
       redirect_to :action => 'index'
     end
index b82667c3f926f6d82f61e3844010744cc2466fdf..9e5709eb77d96c78c67ca050e497a6f92255b93a 100644 (file)
@@ -1,7 +1,11 @@
 class FullVoter < Voter
-  before_create :create_password
   validates_presence_of :email, :password
 
+  def initialize(params={})
+    super
+    create_password
+  end
+  
   def create_password
     token_generator = UniqueTokenGenerator.new( 16 )
     until password and not password.empty? \
index 71b200f603f313db269a5cae7714ebe84af8b957..508902cfc24a92121711ecfbd519ca7bcbb277a3 100644 (file)
@@ -16,7 +16,7 @@ class RawVoterList
   
   def each
     @input_addresses.split("\n").each do |address|
-      yield Voter.new( { :email => address } ) 
+      yield FullVoter.new( { :email => address } ) 
     end
   end
 end
index 4ed9598f15cddc4888a4c32612269ad3f0f124d2..e9f4fd637b94e2e91f533e4a0c1925e803c883d4 100644 (file)
@@ -1,6 +1,6 @@
-class Token < ActiveRecord::Base
-  belongs_to :vote 
-
+class Token < ActiveRecord::Base 
+  belongs_to :vote
+  
   def initialize
     super
 
index 62944e3301a5b6f07f77f475e1ef85ae8d314cc6..dcadcac91d5db2bcd4158825b9098ab7e788e708 100644 (file)
@@ -7,9 +7,7 @@ class Vote < ActiveRecord::Base
   # callbacks
   after_update :save_rankings
   before_destroy :destroy_rankings
-
   
-
   def to_s
     votes.join("")
   end
@@ -76,7 +74,7 @@ class Vote < ActiveRecord::Base
   def votestring=(string="")
     candidate_ids = voter.election.candidates.sort.collect \
       { |candidate| candidate.id.to_i }
-
+      
     rel_votes = string.split("").collect { |vote| vote.to_i }
     
     # covert relative orders to absolute candidate ids
@@ -95,11 +93,12 @@ class Vote < ActiveRecord::Base
     self.votes.collect {|v| cand_relnums[v]}.join("")
   end
 
-  # the following subroutine is used for quickvotes. it creates a vote
-  # with the candidates listed in order of preference based on
-  # alphabetical order. it is meant to be manipulated and then confirmed
-  def set_defaults!
-    self.votes =  voter.election.candidates.sort.collect {|c| c.id }
+  # the following subroutine is used for quickvotes, but need for elections now
+  # too. It creates a vote with the candidates listed in order of preference 
+  # based on alphabetical order. It is meant to be manipulated and then confirmed
+  def set_defaults!  
+    self.votes = voter.election.candidates.sort.collect {|c| c.id }
     self.save
   end
+         
 end
index f229909814c12fbd51beeb120061661ef87a67ec..012c795a075279e68fd362a51f3f376056695d74 100644 (file)
@@ -1,7 +1,12 @@
 class Voter < ActiveRecord::Base
   belongs_to :election
   has_one :vote
-
+  
+  def reset_vote
+    self.vote.destroy
+    self.reload
+  end
+  
   def destroy
     vote.destroy if vote
     super
index 870a2de03d6bb977c9776abd745f7bd66c671d2a..e5bcf07b22b22275675f00fa799d1857042c7d68 100644 (file)
@@ -1,19 +1,19 @@
-<% -%>
 <div id="cand<%= @current_candidate.id %>">
   <li><%=h @current_candidate.name -%>
     <% if @show_details %>
       (<%= link_to_remote "Hide Details",
                          :update => "cand#{@current_candidate.id}",
-                         :url => { :action => :lessinfo_candidate, :id => @current_candidate.id } %>)
+                         :url => { :action => :lessinfo_candidate,
+                                      :id => @current_candidate.id } %>)
       <br />
       <blockquote>
-      <%= h(@current_candidate.description) %>
+      <%=(@current_candidate.description) %>
       </blockquote>
     <% else %>
       (<%= link_to_remote "Show Details",
                          :update => "cand#{@current_candidate.id}",
                          :url => { :action => :moreinfo_candidate,
-                        :id => @current_candidate.id } %>)
+                                              :id => @current_candidate.id } %>)
     <% end %>
   </li>
 </div>
index 74d4c3c96016fbac4718169f230896854e060f13..881c0a5fb84d466a08338d25326793fa9401e18c 100644 (file)
@@ -1,7 +1,7 @@
 <% %>
 <ul id="candidate_list">
   <% @election.candidates.each do |candidate| %>
-    <% @current_candidate = candidate %>
-      <%= render :partial => 'candidate_line' %>
+      <% @current_candidate = candidate %>
+      <%= render(:partial => 'candidate_line')%>
     <% end %>
 </ul>
index d5d7b6cde07e4a4d1ee96146d6d0ec41213f0b16..7d575e960e5301d204e8743b23dcb4f7a6cf5d64 100644 (file)
@@ -1,7 +1,7 @@
 <%= error_messages_for 'election' %>
 
 <!--[form:election]-->
-<p><label for="election_name">Summary</label><br/>
+<p><label for="election_name">Title</label><br/>
 <%= text_field 'election', 'name', :size => 60 %></p>
 
 <p><label for="election_description">Description</label><br/>
index c82840356ced7ce753ab8f1134e431aa7dd4f6d7..efbb37464de953ed289fd9122246800dd87f35de 100644 (file)
@@ -21,7 +21,6 @@
 <div id="control-room" class="main-section">
   <div id="control-room-content">
   <h2>Control Room</h2>
-
   <% if session[:user] %>
     <%= render :partial => 'user_summary' %> 
   <% else %>
diff --git a/app/views/voter/_sortable_vote.rhtml b/app/views/voter/_sortable_vote.rhtml
new file mode 100644 (file)
index 0000000..4154482
--- /dev/null
@@ -0,0 +1,15 @@
+<% %>
+<div id="sortable_list">
+<ol id="rankings-list">
+  <% for ranking in @voter.vote.rankings %>
+    <li class="moveable" id="ranking_<%= ranking.candidate.id %>">
+      <%=h ranking.candidate.name.capitalize %></li>
+  <% end %>
+</ol>
+</div>
+
+<div class="clearbox"></div>
+
+<%= sortable_element 'rankings-list',
+    :url => { :action => "sort_candidates", :id => @voter.vote.id },
+    :complete => visual_effect(:highlight, 'rankings-list') %>
\ No newline at end of file
index b95fc96209151e9c27ade5fce98d281fb940689c..914077ce1d50783317fdf7cb1616bb19083eb441 100644 (file)
 least preferred. Please list <em>all</em> choices in every vote.
 <em>(For example, 123 or 321 or 213, etc.)</em></p>
 
-<% if @voter.election.quickvote? %>
-  <% form_tag(quickaction_url( :ident => @voter.election.name, :action => 'confirm')) do  %>
-<% else %>
-  <%= form_tag :action => 'review', :id => @voter.password %>
-<% end %>
-
+<%= form_tag :action => 'review', :id => @voter.password %>
 <%= text_field :vote, :votestring -%>
 <%= submit_tag "Vote!" %>
-<% end %>
+
 
index 2f1fc22a71f924acceeb9a5a01ce8cd1d0b9ea59..e6ccb26d16f8e55a04cc7d7bc601150a5ebb07ab 100644 (file)
@@ -5,6 +5,9 @@
 <p><strong>Description:</strong></p>
 <blockquote><%= @voter.election.description %></blockquote>
 
-<%= render_partial 'vote' %>
+<%= render :partial => 'vote' %>
 
+<%= render :partial => 'sortable_vote' %>
+
+<%= button_to "Submit Vote", :action => 'review', :id => @voter.password %>
 
index d1eb9dc4a91e32aaa17f8ef36cf6d313927e7d9b..b8b9089f2775500478d97e8baaa17f7923d2539f 100644 (file)
@@ -1,13 +1,14 @@
 <% %>
 
+<% %>
 <h1>Please review your vote carefully before confirming it.</h1>
 
 <p>You have ranked the candidates in the following order (from most
 preferred to least preferred:</p>
 
 <ol>
-  <% for rank in @vote.rankings.sort %>
-  <li><%= rank.candidate.name %> </li>
+  <% for rank in @voter.vote.rankings.sort %>
+  <li><%=h rank.candidate.name.capitalize %> </li>
   <% end %>
 </ol>
 
index b31f1ba44414984e8747cc6c99495f053a43e215..216ddebf15b1df71b0b6a9b3ab838afa6d428a67 100644 (file)
@@ -11,7 +11,7 @@ need to use the following token to log in to selectricity.media.mit.edu:
   <%= @voter.password %>
 
 Alternatively, you can just click this URL:
-  <%= url_for :controller => 'election', :action => 'show', :id => @voter.election.id %>
+  http://selectricity.media.mit.edu<%= url_for :controller => 'election', :action => 'show', :id => @voter.election %>
 
 If you have any questions or if you feel you have received this message
 in error, you should contact:
index 2033ed18c838d6ff1182f07f96e4ce70d2e64153..7d5f405f5662b4fd30038b5f6d712efa0d1b0976 100644 (file)
@@ -58,6 +58,7 @@ create table voters (
  election_id int NOT NULL, 
  session_id varchar(32) DEFAULT NULL,
  ipaddress varchar(32) DEFAULT NULL,
+ `type` varchar(100) NOT NULL,
  constraint fk_election_voter foreign key (election_id) references election(id),
  primary key (id)
 );
index 590425d670859ee07aab24761a30d00f5c780eb2..6c038deadbd2983e1fb2073265ec989248421809 100644 (file)
@@ -74,10 +74,11 @@ ActiveRecord::Schema.define() do
   create_table "voters", :force => true do |t|
     t.column "email",       :string,  :limit => 100
     t.column "password",    :string,  :limit => 100
-    t.column "contacted",   :integer, :limit => 4,   :default => 0, :null => false
-    t.column "election_id", :integer,                               :null => false
+    t.column "contacted",   :integer, :limit => 4,   :default => 0,  :null => false
+    t.column "election_id", :integer,                                :null => false
     t.column "session_id",  :string,  :limit => 32
     t.column "ipaddress",   :string,  :limit => 32
+    t.column "type",        :string,  :limit => 100, :default => "", :null => false
   end
 
   add_index "voters", ["election_id"], :name => "fk_election_voter"

Benjamin Mako Hill || Want to submit a patch?