Files
grecia/app/models/poll/stats.rb
Javi Martín a4461a1a56 Expire the stats cache once per day
When we first started caching the stats, generating them was a process
that took several minutes, so we never expired the cache.

However, there have been cases where we run into issues where the stats
shown on the screen were outdated. That's why we introduced a task to
manually expire the cache.

But now, generating the stats only takes a few seconds, so we can
automatically expire them every day, remove all the logic needed to
manually expire them, and get rid of most of the issues related to the
cache being outdated.

We're expiring them every day because it's the same day we were doing in
public stats (which we removed in commit 631b48f58), only we're using
`expires_at:` to set the expiration time, in order to simplify the code.

Note that, in the test, we're using `travel_to(time)` so the test passes
even when it starts an instant before midnight. We aren't using
`:with_frozen_time` because, in similar cases (although not in this
case, but I'm not sure whether that's intentional), `travel_to` shows
this error:

> Calling `travel_to` with a block, when we have previously already made
> a call to `travel_to`, can lead to confusing time stubbing.
2024-05-17 20:11:16 +02:00

128 lines
3.0 KiB
Ruby

class Poll::Stats
include Statisticable
alias_method :poll, :resource
CHANNELS = Poll::Voter::VALID_ORIGINS
def self.stats_methods
super +
%i[total_valid_votes total_white_votes total_null_votes
total_participants_web total_web_valid total_web_white total_web_null
total_participants_booth total_booth_valid total_booth_white total_booth_null
total_participants_letter total_letter_valid total_letter_white total_letter_null
total_participants_web_percentage total_participants_booth_percentage
total_participants_letter_percentage
valid_percentage_web valid_percentage_booth valid_percentage_letter total_valid_percentage
white_percentage_web white_percentage_booth white_percentage_letter total_white_percentage
null_percentage_web null_percentage_booth null_percentage_letter total_null_percentage]
end
def total_participants
total_participants_web + total_participants_booth
end
def participation_date
poll.ends_at
end
def channels
CHANNELS.select { |channel| send(:"total_participants_#{channel}") > 0 }
end
CHANNELS.each do |channel|
define_method :"total_participants_#{channel}" do
send(:"total_#{channel}_valid") +
send(:"total_#{channel}_white") +
send(:"total_#{channel}_null")
end
define_method :"total_participants_#{channel}_percentage" do
calculate_percentage(send(:"total_participants_#{channel}"), total_participants)
end
end
def total_web_valid
voters.where(origin: "web").count - total_web_white
end
def total_web_white
0
end
def total_web_null
0
end
def total_booth_valid
recounts.sum(:total_amount)
end
def total_booth_white
recounts.sum(:white_amount)
end
def total_booth_null
recounts.sum(:null_amount)
end
def total_letter_valid
voters.where(origin: "letter").count # TODO: count only valid votes
end
def total_letter_white
0 # TODO
end
def total_letter_null
0 # TODO
end
%i[valid white null].each do |type|
CHANNELS.each do |channel|
define_method :"#{type}_percentage_#{channel}" do
calculate_percentage(send(:"total_#{channel}_#{type}"), send(:"total_#{type}_votes"))
end
end
define_method :"total_#{type}_votes" do
send(:"total_web_#{type}") + send(:"total_booth_#{type}")
end
define_method :"total_#{type}_percentage" do
calculate_percentage(send(:"total_#{type}_votes"), total_participants)
end
end
def total_no_demographic_data
super + total_unregistered_booth
end
def total_registered_booth
voters.where(origin: "booth").count
end
private
def participant_ids
voters
end
def voters
@voters ||= poll.voters.select(:user_id)
end
def recounts
@recounts ||= poll.recounts
end
def total_unregistered_booth
[total_participants_booth - total_registered_booth, 0].max
end
stats_cache(*stats_methods)
def full_cache_key_for(key)
"polls_stats/#{poll.id}/#{key}"
end
end