Merge head
[selectricity-live] / app / models / election.rb
1 class Election < ActiveRecord::Base
2   has_many :candidates
3   has_many :voters
4   has_many :votes
5   belongs_to :user
6   validates_presence_of :name, :description
7   
8   #validate that method is one of the listed election types
9   
10   attr_reader :plurality_result
11   attr_reader :approval_result
12   attr_reader :condorcet_result
13   attr_reader :ssd_result
14   attr_reader :borda_result
15   
16   require 'date'
17   
18   def initialize(params={})
19     super
20     self.enddate = read_attribute( :enddate ) || \
21                    Time.now + 30.days - 1.second
22   end
23
24   def other_methods
25     if election_method
26       @other_methods = ELECTION_TYPES.reject {|i| i == election_method}
27     else
28       @other_methods = nil
29     end
30     @other_methods
31   end
32
33   def startdate
34     read_attribute( :startdate ) || Time.now
35   end
36
37   def votes
38     votes = Array.new
39     self.voters.each do |voter|
40       votes << voter.vote
41     end
42     return votes
43   end
44
45   def destroy
46     self.candidates.each do |candidate|
47       candidate.destroy
48     end
49     super
50   end
51
52   def start_blockers
53     reasons = []
54     if self.candidates.length <= 1
55       reasons << "You must have at least two candidates."
56     end
57     
58     if self.voters.length <= 1
59       reasons << "You must have at least two voters."
60     end
61
62     reasons
63   end
64
65   def activate!
66     self.active = 1
67     self.save!
68   end
69   
70   def quickvote?
71     self.class == 'QuickVote'
72   end
73
74   def active?
75     active == 1
76   end 
77
78   def done?
79     active == 2
80   end
81
82   def shortdesc
83     shortdesc = description.split(/\n/)[0]
84   end
85
86   def longdesc
87     longdesc = description.split(/\n/)[1..-1].join("")
88     longdesc.length > 0 ? longdesc : nil 
89   end
90   
91   #Calculate Election Results
92   def results
93     # initalize the tallies to empty arrays
94     preference_tally = Array.new
95     plurality_tally = Array.new
96     approval_tally = Array.new
97
98     self.voters.each do |voter|
99       # skip if the voter has not voted or has an unconfirmed vote
100       next unless voter.voted?
101
102       plurality_tally << voter.vote.rankings.sort[0].candidate.id
103       approval_tally << voter.vote.rankings.sort[0..1].collect \
104         { |ranking| ranking.candidate.id }
105       preference_tally << voter.vote.rankings.sort.collect \
106         { |ranking| ranking.candidate.id }
107     end
108     
109     @plurality_result = PluralityVote.new(plurality_tally).result
110     @approval_result = ApprovalVote.new(approval_tally).result
111     @condorcet_result = PureCondorcetVote.new(preference_tally).result
112     @ssd_result = CloneproofSSDVote.new(preference_tally).result
113     @borda_result = BordaVote.new(preference_tally).result
114     
115     { 'plurality' => @plurality_result,
116       'approval' => @approval_result,
117       'condorcet' => @condorcet_result,
118       'ssd' => @ssd_result,
119       'borda' => @borda_result }
120     end
121   
122   def names_by_id
123     names = Hash.new
124     
125     competitors = self.candidates.sort.collect {|candidate| candidate.id}
126     competitors.each do |candidate|
127       names[candidate] = Candidate.find(candidate).name
128     end
129     
130     names
131   end
132   
133 end
134
135

Benjamin Mako Hill || Want to submit a patch?