Avoid to raise an exception `Module::DelegationError' when trying to
show the name and/or email of a poll officer whose user account has
been deleted.
We'll show a message "User deleted" and "Email deleted" instead.
In Rails 5.1, calling `travel_to` inside another `travel_to` block will
result in a RuntimeError:
> Calling `travel_to` with a block, when we have previously already made
> a call to `travel_to`, can lead to confusing time stubbing.
This table will store which reports (stats, results, ...) will be shown
for a certain process (polls, budgets, ...).
Note Rails fails to save a poll and its report when both are new records
if we add a `validate :process, presence: true` rule. Since it caused a
lot of trouble when creating records for tests during factories rule
completely. Instead, I've created the `results_enabled=` and
`stats_enabled=` methods, so tests are easier to set up, while also
automatically creating a report if it doesn't already exist. This also
decouples form structure and database implemenation.
Originally I named this table `enabled_reports` and instead of having
`stats` and `results` columns, it had an `enabled` column and a `kind`
column, which would be set to "stats" or "results". However, although
that table would allow us to add arbitrary reports easily, I found the
way we had to handle the `has_many` relationship was a bit too complex.
This code might be slightly slower because it performs one query per
field in the form, but I didn't notice any differences on my development
machine, and the code is now much easier to understand.
Due to technical issues, sometimes users voted in booths and their vote
couldn't be added to the database. So we're including them in the users
with no demographic data.
We need a way to manually expire the cache for a budget or poll without
expiring the cache of every budget or poll.
Using the `updated_at` column would be dangerous because most of the
times we update a budget or a poll, we don't need to regenerate their
stats.
We've considered adding a `stats_updated_at` column to each of these
tables. However, in that case we would also need to add a similar column
in the future to every process type whose stats we want to generate.
If users participated and were hidden after participating, we should
still count them in the participants stats.
In the tests, we set users' `hidden_at` attribute before they vote.
Although in real life they would vote first and then they would be
hidden, I've written the tests like this for the sake of simplicity.
This implementation is a bit more robust because we don't have to change
any of the "or_later?" methods if we add or remove a new phase.
We could also use metaprogramming to reduce code duplication in these
methods. So far, I've decided to keep the code simple since the
duplication seems reasonable.
So if we don't have information regarding gender, age or geozone, stats
regarding those topics will not be shown.
Note we're using `spec/models/statisticable_spec.rb` because having the
same file in `spec/models/concerns` caused the tests to be executed
twice.
Also note the implementation behind the `gender?`, `age?` and `geozone?`
methods is a bit primitive. We might need to make it more robust in the
future.
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.
For now we think showing them would be showing too much data and it
would be a bit confusing.
I've been tempted to just remove the view and keep the methods in the
model in case they're used by other institutions using CONSUL. However,
it's probably better to wait until we're asked to re-implement them, and
in the meantime we don't maintain code nobody uses. The code wasn't that
great to start with (I know it because I wrote it).
We were expecting `balloters` to include `poll_ballot_voters` (that's
why we're substracting them to calculate web participants), but reality
has proven `poll_ballot_voters` aren't included in `balloters`.
While we already had "one test to rule all stats", testing each method
individually makes reading, adding and changing tests easier.
Note we need to make all methods being tested public. We could also test
them using methods like `stats.generate[:total_valid_votes]` instead of
`stats.total_valid_votes`, but then the tests would be more difficult to
read.
This spec was leaving the DB "dirty" because it was creating
records in a before(:all) hook. These records are not cleaned up
automatically when using the :transaction strategy for DatabaseCleaner.
Using before(:each), however, causes another problem. Some of the code
depends on the heading id being 1 (see app/models/budget/ballot/line.rb#L48).
Because of SQL auto-increment, this is only the case the first time the hook
is run, as different id's are assigned on subsequent runs. This is fixed
by forcing the id to always be 1.
This code was introduced in commit 722a431b, but it stopped being used
in commit 7657a0e0.
The spec was failing sometimes because the method didn't order the
records, but the spec checked the records returned in a certain order.
Furthermore, the method `page` generated a potential conflict with
kaminari's `page method.