Election results in the London Borough of Sutton.
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

247 строки
7.9 KiB

  1. require 'data_mapper'
  2. class Poll
  3. include DataMapper::Resource
  4. property :district_id, Integer, :key => true
  5. property :election_id, Integer, :key => true
  6. property :electorate, Integer # The number of people eligible to vote in this district in this election
  7. property :ballot_papers_issued, Integer # The number of ballot papers issued (includes spoiled ballots)
  8. property :seats, Integer, :required => true # The number of seats to be elected in this district in this election
  9. property :rejected_no_official_mark, Integer
  10. property :rejected_too_many_candidates, Integer
  11. property :rejected_identifiable_voter, Integer
  12. property :rejected_blank_or_uncertain, Integer
  13. def turnout_percent
  14. @ballot_papers_issued.to_f / @electorate.to_f * 100.0
  15. end
  16. def total_rejected_ballots
  17. @rejected_no_official_mark + \
  18. @rejected_too_many_candidates + \
  19. @rejected_identifiable_voter + \
  20. @rejected_blank_or_uncertain
  21. end
  22. belongs_to :election
  23. belongs_to :district
  24. end
  25. class PollingStation
  26. include DataMapper::Resource
  27. property :id, String, :key => true, :length => 2 # e.g. "KA"
  28. property :name, String, :length => 255#, :required => true
  29. property :address, String, :length => 255#, :required => true
  30. property :postcode, String#, :required => true
  31. property :easting, Float, :required => true
  32. property :northing, Float, :required => true
  33. property :lat, Float, :required => true
  34. property :lng, Float, :required => true
  35. has n, :postcodes
  36. end
  37. class Postcode
  38. include DataMapper::Resource
  39. # Postcode natural key, uppercase with space, eg. "SM1 1EA"
  40. # Column names derived from Ordnance Survey CodePoint Open
  41. property :postcode, String, :key => true
  42. property :positional_quality_indicator, Integer
  43. property :eastings, Integer, :required => true
  44. property :northings, Integer, :required => true
  45. property :country_code, String, :required => true
  46. property :nhs_regional_ha_code, String, :required => true
  47. property :nhs_ha_code, String, :required => true
  48. property :admin_county_code, String # NULL within Greater London
  49. property :admin_district_code, String, :required => true # e.g. London Borough of Sutton
  50. property :admin_ward_code, String, :required => true # e.g. Sutton Central
  51. property :lat, Float, :required => true
  52. property :lng, Float, :required => true
  53. property :ward_id, Integer, :required => true # Sutton Council
  54. property :constituency_id, Integer, :required => false # UK Parliament
  55. property :polling_station_id, String, :length => 2
  56. belongs_to :district, :child_key => [:ward_id]
  57. belongs_to :polling_station
  58. def self.finder(postcode)
  59. postcode = postcode.strip.upcase
  60. if o = self.get(postcode)
  61. return o
  62. end
  63. result = Pat.get(postcode)
  64. unless result.code == 404
  65. # cache API result
  66. self.create(
  67. :postcode => postcode,
  68. :lat => result['geo']['lat'],
  69. :lng => result['geo']['lng'],
  70. :district_name => result['administrative']['district']['title'],
  71. :district_code => result['administrative']['district']['uri'].match(/.+\/(.+)$/)[1],
  72. :ward_name => result['administrative']['ward']['title'],
  73. :ward_code => result['administrative']['ward']['uri'].match(/.+\/(.+)$/)[1]
  74. )
  75. else
  76. # invalid postcode
  77. nil
  78. end
  79. end
  80. end
  81. class Candidate
  82. include DataMapper::Resource
  83. property :id, Serial
  84. property :forenames, String, :required => true
  85. property :surname, String, :required => true, :index => true
  86. has n, :candidacies
  87. def short_name
  88. @forenames.split(' ')[0] + ' ' + @surname
  89. end
  90. def name
  91. @forenames + ' ' + @surname
  92. end
  93. end
  94. class DeletedCandidate
  95. include DataMapper::Resource
  96. property :old_candidate_id, Integer, :key => true # ID of candidate that has been merged/deleted
  97. property :candidate_id, Integer, :required => true # ID of candidate that has been kept
  98. end
  99. class Candidacy
  100. include DataMapper::Resource
  101. property :id, Serial
  102. property :election_id, Integer, :required => true
  103. property :candidate_id, Integer, :required => true
  104. property :party_id, Integer
  105. property :district_id, Integer, :required => true
  106. property :votes, Integer
  107. property :address, String, :length => 200
  108. property :postcode, String
  109. property :position, Integer # Position of this candidate in this district. (1..n)
  110. property :seats, Integer # Number of seats won by this candidacy (0 or 1)
  111. property :labcoop, Boolean, :default => false # Candidacy is for joint Labour/Co-op party
  112. belongs_to :election
  113. belongs_to :candidate
  114. belongs_to :party
  115. belongs_to :district
  116. end
  117. class Campaign
  118. include DataMapper::Resource
  119. property :party_id, Integer, :key => true
  120. property :election_id, Integer, :key => true
  121. property :party_url, String, :length => 255
  122. property :manifesto_html_url, String, :length => 255
  123. property :manifesto_pdf_url, String, :length => 255
  124. belongs_to :party
  125. belongs_to :election
  126. end
  127. class Election
  128. include DataMapper::Resource
  129. property :id, Serial
  130. property :body_id, Integer, :required => true
  131. property :d, Date, :required => true, :index => true
  132. property :reason, String, :length => 255
  133. property :kind, String, :length => 255
  134. has n, :candidacies
  135. has n, :polls
  136. belongs_to :body
  137. has n, :campaigns
  138. def self.past
  139. self.all(:d.lt => Time.now.to_s, :order => [ :d.desc ])
  140. end
  141. def self.future
  142. self.all(:d.gte => Time.now.to_s, :order => [ :d.desc ])
  143. end
  144. # electorate and ballot_papers_issued assume there's a Poll object for every district in this election
  145. def electorate
  146. Poll.sum(:electorate, :election => self)
  147. end
  148. def ballot_papers_issued
  149. Poll.sum(:ballot_papers_issued, :election => self)
  150. end
  151. end
  152. class District
  153. include DataMapper::Resource
  154. property :id, Serial
  155. property :body_id, Integer, :required => true
  156. property :name, String, :length => 255, :required => true
  157. property :slug, String
  158. property :seats, Integer
  159. property :ons_district_code, String
  160. belongs_to :body
  161. has n, :postcodes, :child_key => [:ward_id]
  162. has n, :polls
  163. def self.slugify(name)
  164. name.gsub(/[^\w\s-]/, '').gsub(/\s+/, '-').downcase
  165. end
  166. end
  167. class Body
  168. include DataMapper::Resource
  169. property :id, Serial
  170. property :name, String, :length => 255, :required => true
  171. property :district_name, String, :length => 255, :required => true # singular
  172. property :districts_name, String, :length => 255, :required => true # plural
  173. property :slug, String, :length => 255
  174. has n, :elections
  175. has n, :districts
  176. end
  177. class Party
  178. include DataMapper::Resource
  179. property :id, Serial
  180. property :name, String, :required => true
  181. property :colour, String
  182. has n, :candidacies
  183. has n, :campaigns
  184. end
  185. class Ward
  186. include DataMapper::Resource
  187. property :id, Serial
  188. property :slug, String, :required => true
  189. property :ons_id, String, :required => true
  190. property :name, String, :required => true
  191. def self.slugify(name)
  192. name.gsub(/[^\w\s-]/, '').gsub(/\s+/, '-').downcase
  193. end
  194. end
  195. DataMapper.setup(:default, ENV['DATABASE_URL'] || "postgres://postgres@localhost:5432/suttonelections")
  196. DataMapper.auto_upgrade!