Use stats objects instead of hashes

It will make it far easier to call other methods on the stats object,
and we're already caching the methods.

We had to remove the view fragment caching because the stats object
isn't as easy to cache. The good thing about it is the view will
automatically be updated when we change logic regarding which stats to
show, and the methods taking long to execute are cached in the model.
This commit is contained in:
Javi Martín
2019-03-18 15:38:53 +01:00
parent eba30d1585
commit 76c7827cf4
9 changed files with 244 additions and 290 deletions

View File

@@ -6,16 +6,12 @@ module Budgets
def show def show
authorize! :read_stats, @budget authorize! :read_stats, @budget
@stats = load_stats @stats = Budget::Stats.new(@budget)
@headings = @budget.headings.sort_by_name @headings = @budget.headings.sort_by_name
end end
private private
def load_stats
Budget::Stats.new(@budget).generate
end
def load_budget def load_budget
@budget = Budget.find_by(slug: params[:budget_id]) || Budget.find_by(id: params[:budget_id]) @budget = Budget.find_by(slug: params[:budget_id]) || Budget.find_by(id: params[:budget_id])
end end

View File

@@ -33,7 +33,7 @@ class PollsController < ApplicationController
end end
def stats def stats
@stats = Poll::Stats.new(@poll).generate @stats = Poll::Stats.new(@poll)
end end
def results def results

View File

@@ -13,36 +13,59 @@ class Budget::Stats
User.where(id: (authors + voters + balloters + poll_ballot_voters).uniq.compact) User.where(id: (authors + voters + balloters + poll_ballot_voters).uniq.compact)
end end
def total_participants
participants.distinct.count
end
def total_participants_support_phase
voters.uniq.count
end
def total_participants_vote_phase
(balloters + poll_ballot_voters).uniq.count
end
def total_budget_investments
budget.investments.count
end
def total_votes
budget.ballots.pluck(:ballot_lines_count).inject(0) { |sum, x| sum + x }
end
def total_selected_investments
budget.investments.selected.count
end
def total_unfeasible_investments
budget.investments.unfeasible.count
end
def headings
groups = Hash.new(0)
budget.headings.order("id ASC").each do |heading|
groups[heading.id] = Hash.new(0).merge(calculate_heading_totals(heading))
end
groups[:total] = Hash.new(0)
groups[:total][:total_investments_count] = groups.collect {|_k, v| v[:total_investments_count]}.sum
groups[:total][:total_participants_support_phase] = groups.collect {|_k, v| v[:total_participants_support_phase]}.sum
groups[:total][:total_participants_vote_phase] = groups.collect {|_k, v| v[:total_participants_vote_phase]}.sum
groups[:total][:total_participants_all_phase] = groups.collect {|_k, v| v[:total_participants_all_phase]}.sum
budget.headings.each do |heading|
groups[heading.id].merge!(calculate_heading_stats_with_totals(groups[heading.id], groups[:total], heading.population))
end
groups[:total][:percentage_participants_support_phase] = groups.collect {|_k, v| v[:percentage_participants_support_phase]}.sum
groups[:total][:percentage_participants_vote_phase] = groups.collect {|_k, v| v[:percentage_participants_vote_phase]}.sum
groups[:total][:percentage_participants_all_phase] = groups.collect {|_k, v| v[:percentage_participants_all_phase]}.sum
groups
end
private private
def total_participants
participants.distinct.count
end
def total_participants_support_phase
voters.uniq.count
end
def total_participants_vote_phase
(balloters + poll_ballot_voters).uniq.count
end
def total_budget_investments
budget.investments.count
end
def total_votes
budget.ballots.pluck(:ballot_lines_count).inject(0) { |sum, x| sum + x }
end
def total_selected_investments
budget.investments.selected.count
end
def total_unfeasible_investments
budget.investments.unfeasible.count
end
def authors def authors
budget.investments.pluck(:author_id) budget.investments.pluck(:author_id)
end end
@@ -71,29 +94,6 @@ class Budget::Stats
end end
end end
def headings
groups = Hash.new(0)
budget.headings.order("id ASC").each do |heading|
groups[heading.id] = Hash.new(0).merge(calculate_heading_totals(heading))
end
groups[:total] = Hash.new(0)
groups[:total][:total_investments_count] = groups.collect {|_k, v| v[:total_investments_count]}.sum
groups[:total][:total_participants_support_phase] = groups.collect {|_k, v| v[:total_participants_support_phase]}.sum
groups[:total][:total_participants_vote_phase] = groups.collect {|_k, v| v[:total_participants_vote_phase]}.sum
groups[:total][:total_participants_all_phase] = groups.collect {|_k, v| v[:total_participants_all_phase]}.sum
budget.headings.each do |heading|
groups[heading.id].merge!(calculate_heading_stats_with_totals(groups[heading.id], groups[:total], heading.population))
end
groups[:total][:percentage_participants_support_phase] = groups.collect {|_k, v| v[:percentage_participants_support_phase]}.sum
groups[:total][:percentage_participants_vote_phase] = groups.collect {|_k, v| v[:percentage_participants_vote_phase]}.sum
groups[:total][:percentage_participants_all_phase] = groups.collect {|_k, v| v[:percentage_participants_all_phase]}.sum
groups
end
def calculate_heading_totals(heading) def calculate_heading_totals(heading)
{ {
total_investments_count: heading.investments.count, total_investments_count: heading.investments.count,

View File

@@ -9,7 +9,7 @@ module Statisticable
end end
def generate def generate
self.class.stats_methods.map { |stat_name| [stat_name, send(stat_name)] }.to_h self.class.stats_methods.each { |stat_name| send(stat_name) }
end end
def total_male_participants def total_male_participants

View File

@@ -8,158 +8,156 @@
social_description: @budget.description_finished %> social_description: @budget.description_finished %>
<% end %> <% end %>
<% cache [@stats] do %> <div class="participation-stats budgets-stats">
<div class="participation-stats budgets-stats"> <div class="expanded no-margin-top padding header">
<div class="expanded no-margin-top padding header"> <div class="row">
<div class="row">
<div class="small-12 column">
<%= back_link_to budgets_path %>
<h2 class="margin-top">
<%= t("stats.title") %><br>
<span><%= @budget.name %></span>
</h2>
</div>
</div>
</div>
<div class="row margin-top">
<div class="small-12 column"> <div class="small-12 column">
<ul class="tabs"> <%= back_link_to budgets_path %>
<li class="tabs-title"> <h2 class="margin-top">
<span class="show-for-sr"><%= t("shared.you_are_in") %></span> <%= t("stats.title") %><br>
<%= link_to t("budgets.results.link"), budget_results_path(@budget) %> <span><%= @budget.name %></span>
</li> </h2>
<li class="tabs-title is-active">
<%= link_to t("stats.budgets.link"), budget_stats_path(@budget), class: "is-active" %>
</li>
<li class="tabs-title">
<%= link_to t("budgets.executions.link"), budget_executions_path(@budget) %>
</li>
</ul>
</div> </div>
</div> </div>
</div>
<div class="row margin"> <div class="row margin-top">
<div class="small-12 medium-3 column sidebar"> <div class="small-12 column">
<%= render "shared/stats/links" %> <ul class="tabs">
<li class="tabs-title">
<span class="show-for-sr"><%= t("shared.you_are_in") %></span>
<%= link_to t("budgets.results.link"), budget_results_path(@budget) %>
</li>
<li class="tabs-title is-active">
<%= link_to t("stats.budgets.link"), budget_stats_path(@budget), class: "is-active" %>
</li>
<li class="tabs-title">
<%= link_to t("budgets.executions.link"), budget_executions_path(@budget) %>
</li>
</ul>
</div>
</div>
<p><strong><%= link_to t("stats.advanced"), "#advanced_statistics" %></strong></p> <div class="row margin">
<ul class="menu vertical"> <div class="small-12 medium-3 column sidebar">
<li> <%= render "shared/stats/links" %>
<%= link_to t("stats.budgets.total_investments"), "#total_investments"%>
</li>
<li>
<%= link_to t("stats.budgets.by_phase"), "#stats_by_phase"%>
</li>
<li>
<%= link_to t("stats.budgets.by_heading"), "#stats_by_heading"%>
</li>
</ul>
</div>
<div class="small-12 medium-9 column stats-content"> <p><strong><%= link_to t("stats.advanced"), "#advanced_statistics" %></strong></p>
<%= render "shared/stats/participation", stats: @stats %> <ul class="menu vertical">
<li>
<%= link_to t("stats.budgets.total_investments"), "#total_investments" %>
</li>
<li>
<%= link_to t("stats.budgets.by_phase"), "#stats_by_phase" %>
</li>
<li>
<%= link_to t("stats.budgets.by_heading"), "#stats_by_heading" %>
</li>
</ul>
</div>
<div id="advanced_statistics"> <div class="small-12 medium-9 column stats-content">
<h3 class="section-title"><%= t("stats.advanced") %></h3> <%= render "shared/stats/participation", stats: @stats %>
<div id="total_investments" class="stats-group"> <div id="advanced_statistics">
<h4><%= t("stats.budgets.total_investments") %></h4> <h3 class="section-title"><%= t("stats.advanced") %></h3>
<%= number_with_info_tags( <div id="total_investments" class="stats-group">
@stats[:total_budget_investments], <h4><%= t("stats.budgets.total_investments") %></h4>
t("stats.budgets.total_investments"),
html_class: "total-investments"
) %>
<%= number_with_info_tags(@stats[:total_unfeasible_investments], <%= number_with_info_tags(
t("stats.budgets.total_unfeasible_investments")) %> @stats.total_budget_investments,
<%= number_with_info_tags(@stats[:total_selected_investments], t("stats.budgets.total_investments"),
t("stats.budgets.total_selected_investments")) %> html_class: "total-investments"
</div> ) %>
<div id="stats_by_phase" class="stats-group"> <%= number_with_info_tags(@stats.total_unfeasible_investments,
<h4><%= t("stats.budgets.by_phase") %></h4> t("stats.budgets.total_unfeasible_investments")) %>
<%= number_with_info_tags(@stats.total_selected_investments,
<%= number_with_info_tags(@stats[:total_participants_support_phase], t("stats.budgets.total_selected_investments")) %>
t("stats.budgets.participants_support_phase")) %>
<%= number_with_info_tags(@stats[:total_participants_vote_phase],
t("stats.budgets.participants_voting_phase")) %>
</div>
<div id="stats_by_heading" class="stats-group">
<h4 class="margin-bottom"><%= t("stats.budgets.by_heading") %></h4>
<table class="stats-districts survey-districts">
<thead>
<tr>
<th scope="col" rowspan="2"><%= t("stats.budgets.heading") %></th>
<th scope="col" rowspan="2"><%= t("stats.budgets.investments_sent_html") %></th>
<th scope="col" colspan="3"><%= t("stats.budgets.participants_support_phase") %></th>
<th scope="col" colspan="3"><%= t("stats.budgets.participants_voting_phase") %></th>
<th scope="col" colspan="3"><%= t("stats.budgets.participants_total") %></th>
</tr>
<tr>
<th scope="col" class="tiny"><%= t("stats.budgets.total") %></th>
<th scope="col" class="tiny"><%= t("stats.budgets.percent_total_participants_html") %></th>
<th scope="col" class="tiny"><%= t("stats.budgets.percent_heading_census_html") %></th>
<th scope="col" class="tiny"><%= t("stats.budgets.total") %></th>
<th scope="col" class="tiny"><%= t("stats.budgets.percent_total_participants_html") %></th>
<th scope="col" class="tiny"><%= t("stats.budgets.percent_heading_census_html") %></th>
<th scope="col" class="tiny"><%= t("stats.budgets.total") %></th>
<th scope="col" class="tiny"><%= t("stats.budgets.percent_total_participants_html") %></th>
<th scope="col" class="tiny"><%= t("stats.budgets.percent_heading_census_html") %></th>
</tr>
</thead>
<tbody id="headings">
<% @headings.each do |heading| %>
<tr id="<%= heading.name.parameterize %>">
<td class="border-left">
<strong><%= heading.name %></strong>
</td>
<td id="total_spending_proposals_heading_<%= heading.id %>"
class="text-center border-left border-right">
<%= @stats[:headings][heading.id][:total_investments_count] %>
</td>
<% ["support", "vote", "all"].each do |phase| %>
<td id="total_participants_<%= phase %>_phase_heading_<%= heading.id %>"
class="border-left text-center">
<%= @stats[:headings][heading.id]["total_participants_#{phase}_phase".to_sym] %>
</td>
<td id="percentage_participants_<%= phase %>_phase_heading_<%= heading.id %>"
class="border-left border-right text-center">
<%= number_to_stats_percentage(@stats[:headings][heading.id]["percentage_participants_#{phase}_phase".to_sym]) %>
</td>
<td id="percentage_district_population_<%= phase %>_phase_heading_<%= heading.id %>"
class="text-center border-right">
<%= number_to_stats_percentage(@stats[:headings][heading.id]["percentage_district_population_#{phase}_phase".to_sym]) %>
</td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
</div>
</div> </div>
<div class="row margin"> <div id="stats_by_phase" class="stats-group">
<div class="small-12 column"> <h4><%= t("stats.budgets.by_phase") %></h4>
<div id="total_unknown_gender_or_age">
<p class="help-text"> <%= number_with_info_tags(@stats.total_participants_support_phase,
<%= t("stats.budgets.no_demographic_data", total: @stats[:total_unknown_gender_or_age]) %> t("stats.budgets.participants_support_phase")) %>
</p> <%= number_with_info_tags(@stats.total_participants_vote_phase,
<p class="help-text"> t("stats.budgets.participants_voting_phase")) %>
<%= t("stats.budgets.participatory_disclaimer") %>
</p> </div>
<p class="help-text">
<%= t("stats.budgets.heading_disclaimer") %> <div id="stats_by_heading" class="stats-group">
</p> <h4 class="margin-bottom"><%= t("stats.budgets.by_heading") %></h4>
</div>
<table class="stats-districts survey-districts">
<thead>
<tr>
<th scope="col" rowspan="2"><%= t("stats.budgets.heading") %></th>
<th scope="col" rowspan="2"><%= t("stats.budgets.investments_sent_html") %></th>
<th scope="col" colspan="3"><%= t("stats.budgets.participants_support_phase") %></th>
<th scope="col" colspan="3"><%= t("stats.budgets.participants_voting_phase") %></th>
<th scope="col" colspan="3"><%= t("stats.budgets.participants_total") %></th>
</tr>
<tr>
<th scope="col" class="tiny"><%= t("stats.budgets.total") %></th>
<th scope="col" class="tiny"><%= t("stats.budgets.percent_total_participants_html") %></th>
<th scope="col" class="tiny"><%= t("stats.budgets.percent_heading_census_html") %></th>
<th scope="col" class="tiny"><%= t("stats.budgets.total") %></th>
<th scope="col" class="tiny"><%= t("stats.budgets.percent_total_participants_html") %></th>
<th scope="col" class="tiny"><%= t("stats.budgets.percent_heading_census_html") %></th>
<th scope="col" class="tiny"><%= t("stats.budgets.total") %></th>
<th scope="col" class="tiny"><%= t("stats.budgets.percent_total_participants_html") %></th>
<th scope="col" class="tiny"><%= t("stats.budgets.percent_heading_census_html") %></th>
</tr>
</thead>
<tbody id="headings">
<% @headings.each do |heading| %>
<tr id="<%= heading.name.parameterize %>">
<td class="border-left">
<strong><%= heading.name %></strong>
</td>
<td id="total_spending_proposals_heading_<%= heading.id %>"
class="text-center border-left border-right">
<%= @stats.headings[heading.id][:total_investments_count] %>
</td>
<% ["support", "vote", "all"].each do |phase| %>
<td id="total_participants_<%= phase %>_phase_heading_<%= heading.id %>"
class="border-left text-center">
<%= @stats.headings[heading.id]["total_participants_#{phase}_phase".to_sym] %>
</td>
<td id="percentage_participants_<%= phase %>_phase_heading_<%= heading.id %>"
class="border-left border-right text-center">
<%= number_to_stats_percentage(@stats.headings[heading.id]["percentage_participants_#{phase}_phase".to_sym]) %>
</td>
<td id="percentage_district_population_<%= phase %>_phase_heading_<%= heading.id %>"
class="text-center border-right">
<%= number_to_stats_percentage(@stats.headings[heading.id]["percentage_district_population_#{phase}_phase".to_sym]) %>
</td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
<div class="row margin">
<div class="small-12 column">
<div id="total_unknown_gender_or_age">
<p class="help-text">
<%= t("stats.budgets.no_demographic_data", total: @stats.total_unknown_gender_or_age) %>
</p>
<p class="help-text">
<%= t("stats.budgets.participatory_disclaimer") %>
</p>
<p class="help-text">
<%= t("stats.budgets.heading_disclaimer") %>
</p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<% end %> </div>

View File

@@ -31,9 +31,9 @@
<% Poll::Stats::CHANNELS.each do |channel| %> <% Poll::Stats::CHANNELS.each do |channel| %>
<%= number_with_info_tags( <%= number_with_info_tags(
@stats[:"total_participants_#{channel}"], @stats.send("total_participants_#{channel}"),
t("stats.polls.#{channel}_percentage", t("stats.polls.#{channel}_percentage",
percentage: number_to_stats_percentage(@stats[:"total_participants_#{channel}_percentage"]) percentage: number_to_stats_percentage(@stats.send(:"total_participants_#{channel}_percentage"))
), ),
html_class: channel html_class: channel
) %> ) %>
@@ -59,14 +59,14 @@
<% Poll::Stats::CHANNELS.each do |channel| %> <% Poll::Stats::CHANNELS.each do |channel| %>
<td> <td>
<%= @stats[:"total_#{channel}_valid"] %> <%= @stats.send(:"total_#{channel}_valid") %>
<small><em>(<%= @stats[:"valid_percentage_#{channel}"].round(2) %>%)</em></small> <small><em>(<%= @stats.send(:"valid_percentage_#{channel}").round(2) %>%)</em></small>
</td> </td>
<% end %> <% end %>
<td> <td>
<%= @stats[:total_valid_votes] %> <%= @stats.total_valid_votes %>
<small><em>(<%= @stats[:total_valid_percentage].round(2) %>%)</em></small> <small><em>(<%= @stats.total_valid_percentage.round(2) %>%)</em></small>
</td> </td>
</tr> </tr>
@@ -75,13 +75,13 @@
<% Poll::Stats::CHANNELS.each do |channel| %> <% Poll::Stats::CHANNELS.each do |channel| %>
<td> <td>
<%= @stats[:"total_#{channel}_white"] %> <%= @stats.send(:"total_#{channel}_white") %>
<small><em>(<%= @stats[:"white_percentage_#{channel}"].round(2) %>%)</em></small> <small><em>(<%= @stats.send(:"white_percentage_#{channel}").round(2) %>%)</em></small>
</td> </td>
<% end %> <% end %>
<td><%= @stats[:total_white_votes] %> <td><%= @stats.total_white_votes %>
<small><em>(<%= @stats[:total_white_percentage].round(2) %>%)</em></small> <small><em>(<%= @stats.total_white_percentage.round(2) %>%)</em></small>
</td> </td>
</tr> </tr>
<tr> <tr>
@@ -89,14 +89,14 @@
<% Poll::Stats::CHANNELS.each do |channel| %> <% Poll::Stats::CHANNELS.each do |channel| %>
<td> <td>
<%= @stats[:"total_#{channel}_null"] %> <%= @stats.send(:"total_#{channel}_null") %>
<small><em>(<%= @stats[:"null_percentage_#{channel}"].round(2) %>%)</em></small> <small><em>(<%= @stats.send(:"null_percentage_#{channel}").round(2) %>%)</em></small>
</td> </td>
<% end %> <% end %>
<td> <td>
<%= @stats[:total_null_votes] %> <%= @stats.total_null_votes %>
<small><em>(<%= @stats[:total_null_percentage].round(2) %>%)</em></small> <small><em>(<%= @stats.total_null_percentage.round(2) %>%)</em></small>
</td> </td>
</tr> </tr>
<tr> <tr>
@@ -104,12 +104,12 @@
<% Poll::Stats::CHANNELS.each do |channel| %> <% Poll::Stats::CHANNELS.each do |channel| %>
<td> <td>
<%= @stats[:"total_participants_#{channel}"] %> <%= @stats.send(:"total_participants_#{channel}") %>
<small><em>(<%= @stats[:"total_participants_#{channel}_percentage"].round(2) %>%)</em></small> <small><em>(<%= @stats.send(:"total_participants_#{channel}_percentage").round(2) %>%)</em></small>
</td> </td>
<% end %> <% end %>
<td><%= @stats[:total_participants] %></td> <td><%= @stats.total_participants %></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@@ -5,7 +5,7 @@
<h4><%= t("stats.total_participants") %></h4> <h4><%= t("stats.total_participants") %></h4>
<%= number_with_info_tags( <%= number_with_info_tags(
stats[:total_participants], stats.total_participants,
"", "",
html_class: "participants total-participants" html_class: "participants total-participants"
) %> ) %>
@@ -15,14 +15,14 @@
<h4><%= t("stats.by_gender") %></h4> <h4><%= t("stats.by_gender") %></h4>
<%= number_with_info_tags( <%= number_with_info_tags(
stats[:total_male_participants], stats.total_male_participants,
t("stats.men_percentage", percentage: number_to_stats_percentage(stats[:male_percentage])), t("stats.men_percentage", percentage: number_to_stats_percentage(stats.male_percentage)),
html_class: "participants male" html_class: "participants male"
) %> ) %>
<%= number_with_info_tags( <%= number_with_info_tags(
stats[:total_female_participants], stats.total_female_participants,
t("stats.women_percentage", percentage: number_to_stats_percentage(stats[:female_percentage])), t("stats.women_percentage", percentage: number_to_stats_percentage(stats.female_percentage)),
html_class: "participants female" html_class: "participants female"
) %> ) %>
</div> </div>
@@ -39,7 +39,7 @@
</thead> </thead>
<tbody> <tbody>
<% stats[:participants_by_age].values.each do |group| %> <% stats.participants_by_age.values.each do |group| %>
<tr> <tr>
<td><%= group[:range] %></td> <td><%= group[:range] %></td>
<td> <td>
@@ -70,7 +70,7 @@
</thead> </thead>
<tbody> <tbody>
<% stats[:participants_by_geozone].each do |geozone, participants| %> <% stats.participants_by_geozone.each do |geozone, participants| %>
<tr> <tr>
<td><%= geozone %></td> <td><%= geozone %></td>
<td><%= "#{participants[:total][:count]} (#{number_to_stats_percentage(participants[:total][:percentage])})" %></td> <td><%= "#{participants[:total][:count]} (#{number_to_stats_percentage(participants[:total][:percentage])})" %></td>

View File

@@ -33,7 +33,7 @@ describe Budget::Stats do
expect(stats.participants).to match_array( expect(stats.participants).to match_array(
[author, author_and_voter, voter, voter_and_balloter, balloter, poll_balloter] [author, author_and_voter, voter, voter_and_balloter, balloter, poll_balloter]
) )
expect(stats.generate[:total_participants]).to be 6 expect(stats.total_participants).to be 6
end end
end end
@@ -42,7 +42,7 @@ describe Budget::Stats do
2.times { create(:vote, votable: investment) } 2.times { create(:vote, votable: investment) }
create(:budget_ballot_line, investment: investment) create(:budget_ballot_line, investment: investment)
expect(stats.generate[:total_participants_support_phase]).to be 2 expect(stats.total_participants_support_phase).to be 2
end end
it "counts a user who is voter and balloter" do it "counts a user who is voter and balloter" do
@@ -50,7 +50,7 @@ describe Budget::Stats do
create(:vote, votable: investment, voter: voter_and_balloter) create(:vote, votable: investment, voter: voter_and_balloter)
create(:budget_ballot_line, investment: investment, user: voter_and_balloter) create(:budget_ballot_line, investment: investment, user: voter_and_balloter)
expect(stats.generate[:total_participants_support_phase]).to be 1 expect(stats.total_participants_support_phase).to be 1
end end
end end
@@ -59,7 +59,7 @@ describe Budget::Stats do
2.times { create(:budget_ballot_line, investment: investment) } 2.times { create(:budget_ballot_line, investment: investment) }
create(:vote, votable: investment) create(:vote, votable: investment)
expect(stats.generate[:total_participants_vote_phase]).to be 2 expect(stats.total_participants_vote_phase).to be 2
end end
it "counts a user who is voter and balloter" do it "counts a user who is voter and balloter" do
@@ -67,14 +67,14 @@ describe Budget::Stats do
create(:vote, votable: investment, voter: voter_and_balloter) create(:vote, votable: investment, voter: voter_and_balloter)
create(:budget_ballot_line, investment: investment, user: voter_and_balloter) create(:budget_ballot_line, investment: investment, user: voter_and_balloter)
expect(stats.generate[:total_participants_vote_phase]).to be 1 expect(stats.total_participants_vote_phase).to be 1
end end
it "includes balloters and poll balloters" do it "includes balloters and poll balloters" do
create(:budget_ballot_line, investment: investment) create(:budget_ballot_line, investment: investment)
create(:poll_voter, :from_booth, budget: budget) create(:poll_voter, :from_booth, budget: budget)
expect(stats.generate[:total_participants_vote_phase]).to be 2 expect(stats.total_participants_vote_phase).to be 2
end end
it "counts once a user who is balloter and poll balloter" do it "counts once a user who is balloter and poll balloter" do
@@ -82,7 +82,7 @@ describe Budget::Stats do
create(:budget_ballot_line, investment: investment, user: poller_and_balloter) create(:budget_ballot_line, investment: investment, user: poller_and_balloter)
create(:poll_voter, :from_booth, user: poller_and_balloter, budget: budget) create(:poll_voter, :from_booth, user: poller_and_balloter, budget: budget)
expect(stats.generate[:total_participants_vote_phase]).to be 1 expect(stats.total_participants_vote_phase).to be 1
end end
it "doesn't count nil user ids" do it "doesn't count nil user ids" do
@@ -90,7 +90,7 @@ describe Budget::Stats do
ballot: create(:budget_ballot, budget: budget, user: nil, physical: true) ballot: create(:budget_ballot, budget: budget, user: nil, physical: true)
) )
expect(stats.generate[:total_participants_vote_phase]).to be 0 expect(stats.total_participants_vote_phase).to be 0
end end
end end
@@ -99,7 +99,7 @@ describe Budget::Stats do
2.times { create(:budget_investment, budget: budget) } 2.times { create(:budget_investment, budget: budget) }
create(:budget_investment, budget: create(:budget)) create(:budget_investment, budget: create(:budget))
expect(stats.generate[:total_budget_investments]).to be 2 expect(stats.total_budget_investments).to be 2
end end
end end
@@ -108,7 +108,7 @@ describe Budget::Stats do
create(:budget_ballot_line, investment: investment) create(:budget_ballot_line, investment: investment)
create(:budget_ballot_line, investment: create(:budget_investment, :selected, budget: budget)) create(:budget_ballot_line, investment: create(:budget_investment, :selected, budget: budget))
expect(stats.generate[:total_votes]).to be 2 expect(stats.total_votes).to be 2
end end
end end
@@ -118,7 +118,7 @@ describe Budget::Stats do
create(:budget_investment, :selected, budget: create(:budget)) create(:budget_investment, :selected, budget: create(:budget))
create(:budget_investment, :unfeasible, budget: budget) create(:budget_investment, :unfeasible, budget: budget)
expect(stats.generate[:total_selected_investments]).to be 3 expect(stats.total_selected_investments).to be 3
end end
end end
@@ -128,7 +128,7 @@ describe Budget::Stats do
create(:budget_investment, :unfeasible, budget: create(:budget)) create(:budget_investment, :unfeasible, budget: create(:budget))
create(:budget_investment, :selected, budget: budget) create(:budget_investment, :selected, budget: budget)
expect(stats.generate[:total_unfeasible_investments]).to be 3 expect(stats.total_unfeasible_investments).to be 3
end end
end end
@@ -143,31 +143,31 @@ describe Budget::Stats do
describe "#total_male_participants" do describe "#total_male_participants" do
it "returns the number of total male participants" do it "returns the number of total male participants" do
expect(stats.generate[:total_male_participants]).to be 3 expect(stats.total_male_participants).to be 3
end end
end end
describe "#total_female_participants" do describe "#total_female_participants" do
it "returns the number of total female participants" do it "returns the number of total female participants" do
expect(stats.generate[:total_female_participants]).to be 2 expect(stats.total_female_participants).to be 2
end end
end end
describe "#total_unknown_gender_or_age" do describe "#total_unknown_gender_or_age" do
it "returns the number of total unknown participants' gender or age" do it "returns the number of total unknown participants' gender or age" do
expect(stats.generate[:total_unknown_gender_or_age]).to be 1 expect(stats.total_unknown_gender_or_age).to be 1
end end
end end
describe "#male_percentage" do describe "#male_percentage" do
it "returns the percentage of male participants" do it "returns the percentage of male participants" do
expect(stats.generate[:male_percentage]).to be 60.0 expect(stats.male_percentage).to be 60.0
end end
end end
describe "#female_percentage" do describe "#female_percentage" do
it "returns the percentage of female participants" do it "returns the percentage of female participants" do
expect(stats.generate[:female_percentage]).to be 40.0 expect(stats.female_percentage).to be 40.0
end end
end end
end end
@@ -182,18 +182,18 @@ describe Budget::Stats do
end end
it "returns the age groups hash" do it "returns the age groups hash" do
expect(stats.generate[:participants_by_age]["16 - 19"][:count]).to be 0 expect(stats.participants_by_age["16 - 19"][:count]).to be 0
expect(stats.generate[:participants_by_age]["20 - 24"][:count]).to be 4 expect(stats.participants_by_age["20 - 24"][:count]).to be 4
expect(stats.generate[:participants_by_age]["25 - 29"][:count]).to be 0 expect(stats.participants_by_age["25 - 29"][:count]).to be 0
expect(stats.generate[:participants_by_age]["30 - 34"][:count]).to be 1 expect(stats.participants_by_age["30 - 34"][:count]).to be 1
expect(stats.generate[:participants_by_age]["35 - 39"][:count]).to be 0 expect(stats.participants_by_age["35 - 39"][:count]).to be 0
expect(stats.generate[:participants_by_age]["40 - 44"][:count]).to be 3 expect(stats.participants_by_age["40 - 44"][:count]).to be 3
expect(stats.generate[:participants_by_age]["45 - 49"][:count]).to be 0 expect(stats.participants_by_age["45 - 49"][:count]).to be 0
expect(stats.generate[:participants_by_age]["50 - 54"][:count]).to be 2 expect(stats.participants_by_age["50 - 54"][:count]).to be 2
expect(stats.generate[:participants_by_age]["55 - 59"][:count]).to be 0 expect(stats.participants_by_age["55 - 59"][:count]).to be 0
expect(stats.generate[:participants_by_age]["60 - 64"][:count]).to be 0 expect(stats.participants_by_age["60 - 64"][:count]).to be 0
expect(stats.generate[:participants_by_age]["65 - 69"][:count]).to be 0 expect(stats.participants_by_age["65 - 69"][:count]).to be 0
expect(stats.generate[:participants_by_age]["70 - 74"][:count]).to be 0 expect(stats.participants_by_age["70 - 74"][:count]).to be 0
end end
end end
@@ -206,7 +206,7 @@ describe Budget::Stats do
end end
it "returns headings data" do it "returns headings data" do
heading_stats = stats.generate[:headings][investment.heading.id] heading_stats = stats.headings[investment.heading.id]
expect(heading_stats[:total_investments_count]).to be 2 expect(heading_stats[:total_investments_count]).to be 2
expect(heading_stats[:total_participants_support_phase]).to be 2 expect(heading_stats[:total_participants_support_phase]).to be 2
expect(heading_stats[:total_participants_vote_phase]).to be 1 expect(heading_stats[:total_participants_vote_phase]).to be 1

View File

@@ -183,44 +183,4 @@ describe Poll::Stats do
expect(stats.participants_by_geozone["Midgar"][:percentage]).to eq(33.333) expect(stats.participants_by_geozone["Midgar"][:percentage]).to eq(33.333)
end end
end end
end
describe "#generate" do
it "generates the correct stats" do
poll = create(:poll)
2.times { create(:poll_voter, :from_web, poll: poll) }
3.times { create(:poll_voter, :from_booth, poll: poll) }
create(:poll_recount, :from_booth, poll: poll,
white_amount: 1, null_amount: 0, total_amount: 2)
stats = Poll::Stats.new(poll).generate
expect(stats[:total_participants]).to eq(5)
expect(stats[:total_participants_web]).to eq(2)
expect(stats[:total_participants_booth]).to eq(3)
expect(stats[:total_valid_votes]).to eq(4)
expect(stats[:total_white_votes]).to eq(1)
expect(stats[:total_null_votes]).to eq(0)
expect(stats[:total_web_valid]).to eq(2)
expect(stats[:total_web_white]).to eq(0)
expect(stats[:total_web_null]).to eq(0)
expect(stats[:total_booth_valid]).to eq(2)
expect(stats[:total_booth_white]).to eq(1)
expect(stats[:total_booth_null]).to eq(0)
expect(stats[:total_participants_web_percentage]).to eq(40)
expect(stats[:total_participants_booth_percentage]).to eq(60)
expect(stats[:valid_percentage_web]).to eq(50)
expect(stats[:white_percentage_web]).to eq(0)
expect(stats[:null_percentage_web]).to eq(0)
expect(stats[:valid_percentage_booth]).to eq(50)
expect(stats[:white_percentage_booth]).to eq(100)
expect(stats[:null_percentage_booth]).to eq(0)
expect(stats[:total_valid_percentage]).to eq(80)
expect(stats[:total_white_percentage]).to eq(20)
expect(stats[:total_null_percentage]).to eq(0)
end
end
end