bef35020a45b1a7d37ca25fdd86dec73259f8ab5
[selectricity-live] / app / models / vote.rb
1 # Selectricity: Voting Machinery for the Masses
2 # Copyright (C) 2007, 2008 Benjamin Mako Hill <mako@atdot.cc>
3 # Copyright (C) 2007 Massachusetts Institute of Technology
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 # Affero General Public License for more details.
14 #
15 # You should have received a copy of the GNU Affero General Public
16 # License along with this program.  If not, see
17 # <http://www.gnu.org/licenses/>.
18
19 class Vote < ActiveRecord::Base
20   # relationships to other classes
21   belongs_to :voter
22   has_many :rankings
23   has_one :token
24   
25   # callbacks
26   after_update :save_rankings
27   before_destroy :destroy_rankings
28   
29   def to_s
30     votes.join("")
31   end
32
33   def each
34     self.votes.each {|vote| yield vote}
35   end
36
37   def votes
38     unless @votes
39       if rankings.empty?
40         @votes = Array.new
41       else
42         @votes = rankings.sort.collect { |ranking| ranking.candidate.id }
43       end
44     end
45
46     @votes
47   end
48
49   def votes=(array)
50     @votes = array
51   end
52
53   def save_rankings
54     destroy_rankings
55     self.votes.each_with_index do |candidate_id, index| 
56       ranking = Ranking.new
57       ranking.rank = index
58       ranking.candidate =  Candidate.find(candidate_id)
59       self.rankings << ranking
60     end
61   end
62   
63   def destroy
64     self.destroy_rankings
65     super
66   end
67
68   def destroy_rankings 
69     rankings.each { |ranking| ranking.destroy }
70   end
71
72   def confirm!
73     self.confirmed = 1
74     self.time = Time.now
75     self.save
76     
77     unless self.voter.election.quickvote?
78       token.destroy and token.reload if token
79       self.token = Token.new
80       self.save
81     end
82   end
83
84   def confirm?
85     confirmed == 1
86   end
87   
88   def votestring
89     # create a mapping of candidates ids and the relative order of the
90     # candidates as they appear when sorted alphabetically
91     cand_relnums = {}
92     self.voter.election.candidates.sort.each_with_index do |c, i|
93       cand_relnums[c.id] = i + 1
94     end
95
96     # assemble the votestring
97     self.votes.collect {|v| (cand_relnums[v] + 64).chr}.join("")
98   end
99
100   # the following subroutine is used for quickvotes, but need for elections now
101   # too. It creates a vote with the candidates listed in order of preference 
102   # based on alphabetical order. Meant to be manipulated and then confirmed
103   def set_defaults!  
104     self.votes = self.voter.election.candidates.sort_by { rand }.collect {|c| c.id }
105     self.save
106   end
107          
108 end

Benjamin Mako Hill || Want to submit a patch?