Commit Graph

165 Commits

Author SHA1 Message Date
Javi Martín
45a3d8daf0 Add option to enable advanced stats 2019-05-22 11:50:03 +02:00
Javi Martín
1c2e38ea00 Use metaprogramming for report methods
We're going to add an `advanced_stats` report, and having 3 identical
sets of methods would be too much duplication.
2019-05-22 11:50:03 +02:00
Javi Martín
354b183e17 Create reports
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.
2019-05-22 11:50:03 +02:00
Javi Martín
483ebffb47 Fix statisticable concern definition
Methods defined inside "included" cannot be called using `super` from
a class including the module.
2019-05-21 13:50:19 +02:00
Javi Martín
aa0e813970 Use ruby cache for stats helper methods
These methods are only used while stats are being generated; once stats
are generated, they aren't used anymore. So there's no need to store
them using the Dalli cache.

Furthermore, there are polls (and even budgets) with hundreds of
thousands of participants. Calculating stats for them takes a very long
time because we can't store all those records in the Dalli cache.

However, since these records aren't used once the stats are generated,
we can store them in an instance variable while we generate the stats,
speeding up the process.
2019-05-21 13:50:19 +02:00
Javi Martín
7c0e499eee Add table to store stats versions
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.
2019-05-21 13:50:19 +02:00
Javi Martín
9335c51cfc Include hidden users in stats
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.
2019-05-21 13:50:19 +02:00
Javi Martín
1f4707facd Extract method to get stats participant_ids
This way we can share the `participants` method between budget and poll
stats.
2019-05-21 13:50:19 +02:00
Javi Martín
ae4cd06c24 Include no geozone in no demographic data 2019-05-21 13:50:18 +02:00
Javi Martín
383909e16c Extract class to manage GeozoneStats
Even if this class looks very simple now, we're trying a few things
related to these stats. Having a class for it makes future changes
easier and, if there weren't any future changes, at least it makes
current experiments easier.

Note we keep the method `participants_by_geozone` to return a hash
because we're caching the stats and storing GeozoneStats objects would
need a lot more memory and we would get an error.
2019-05-21 13:50:18 +02:00
Javi Martín
558070d530 Remove geozone participation percentage
We currently don't store geozone population.
2019-05-21 13:50:18 +02:00
Javi Martín
793bfed372 Display only existing stats
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.
2019-05-21 13:50:18 +02:00
Javi Martín
76c7827cf4 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.
2019-05-21 13:50:18 +02:00
Javi Martín
e3063cd24f Remove complex poll stats
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).
2019-05-21 13:50:17 +02:00
Javi Martín
8f69113233 Add poll stats by geozone and channel 2019-05-21 13:50:17 +02:00
Javi Martín
202fb44008 Add poll stats by age and channel 2019-05-21 13:50:17 +02:00
Javi Martín
7b408a4b88 Add poll stats by gender and channel 2019-05-21 13:50:17 +02:00
Javi Martín
90fe746d27 Add geozone stats to polls 2019-05-21 13:50:16 +02:00
Javi Martín
a552645e7f Add tests to poll stats
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.
2019-05-21 13:50:16 +02:00
Javi Martín
4d520a3a47 Rename age_groups method
The name was confusing because it seemed to return a list of age groups.
2019-05-21 13:50:16 +02:00
Javi Martín
88daaee9fe Simplify code 2019-05-21 13:50:16 +02:00
Javi Martín
9a01ff5323 Refactor age groups method
We try to make the method return data which is easier to handle in the
view.
2019-05-21 13:50:15 +02:00
Javi Martín
c1b76a7ebf Simplify age groups method 2019-05-21 13:50:15 +02:00
Javi Martín
c2489e3209 Increase number of age groups
We would now like to differenciate between 70-year-old people and
90-year-old people.
2019-05-21 13:50:15 +02:00
Javi Martín
e4a032ee68 Split common and specific stats methods 2019-05-21 13:49:42 +02:00
Javi Martín
5d2f5d1d81 Move gender and age methods to a common concern
These are generic methods which only depend on the participants.
2019-05-21 13:49:42 +02:00
Javi Martín
04c920c27d Simplify calculate percentage method 2019-05-21 13:49:42 +02:00
Javi Martín
ccaa2e1a77 Remove duplication to calculate percentage 2019-05-21 13:49:42 +02:00
Javi Martín
188278296c Simplify the way we cache stats 2019-05-21 13:48:54 +02:00
Javi Martín
d627215af4 Use symbols for method names 2019-05-21 13:27:03 +02:00
Javi Martín
313ffb589b Share method to generate stats 2019-05-21 13:27:03 +02:00
Javi Martín
62a97f9003 Add a common concern for budget and poll stats 2019-05-21 13:27:03 +02:00
decabeza
cb22e6cbfb Merge branch 'master' into proposal-dashboard 2019-04-23 17:12:47 +02:00
Julian Herrero
c9752e94be Change the way we retrireve the images urls
For some reason the paperclip method `attachment.exists?' was
returning nil even when `attachment.url(style)' was correctly
returning the url/path of the attachment.

Therefore returning `nil' was causing to raise an error in the
method `image_tag'.

With this change we make sure we return the image url it it's
available, or an empty string if it's not, but never a null value.
2019-04-17 17:40:56 +02:00
Julian Herrero
6e88031537 Fix several rubocop warnings
Metrics/LineLength: Line is too long.
RSpec/InstanceVariable: Use let instead of an instance variable.
Layout/TrailingBlankLines: Final newline missing.
Style/StringLiterals: Prefer double-quoted strings.
2019-04-17 17:40:56 +02:00
Senén Rodero Rodríguez
aa3e8c8458 Keep method for not yet globalizable models
Maintain the method for models that are still translatable. This help
me to pass the CI build. In later PR's this method will be eliminated
as no one will invoke it.
2019-04-17 17:40:56 +02:00
Senén Rodero Rodríguez
0b3a3b97f7 Santitize description translations
Sanitize all not marked for destruction translations when description
is a translatable attribute.
2019-04-17 17:40:56 +02:00
Senén Rodero Rodríguez
a68098eaed Fix sanitization for translatable description attribute
Move method from sanitizable to globalizable concern because
globalize_accessors were overiding sanitizable method and was never
called. Another solution to this could be to load sanitizable
always after globalizable concern.

Old method implementation was not working well with globalize_accessors,
it was returning nil always.
2019-04-17 17:40:56 +02:00
Senén Rodero Rodríguez
700f271a36 Remove milestone overrided translation class
Since Globalize gem update to v5.2.0 we cannot override translations
anymore in the same way that before the update. Milestone::Translation
class removed in this commit were no longer loaded correctly when
translation class is retrieved by translation_class method provided by
Globalize. Here is the diff between both gem versions:

https://github.com/globalize/globalize/compare/v5.0.0...v5.2.0#diff-a1370b109e0dd567545b072bc6447b8fR51

This problem is not happening on test environment but is throwing an
exception in other environments as it has not loaded the delegation
definition inside our custom translation class.

To fix this we added a new class method inside globalizable model
concern to allow to define method delegation on translations classes from
parent globalizable classes when needed without having to override
Translation classes.

Another way to properly load our custom Milestone::Translation class is
to place it inside parent model class, like the example below:

class Milestone
...

  class Translation
    delegate :status_id, to: :globalized_model
  end
end

Or maybe monkey patching translation_class method from globalize gem
to make it find our custom translation class. I don't like this option.
2019-04-16 17:28:07 +02:00
Javi Martín
74088ac949 Make random IDs with the same seed consistent
The order of the array before being shuffled needs to be the same if we
want to have the same array after being shuffled with a certain seed.

We were using `pluck(:id)`, which doesn't guarantee the order of the
elements returned.

Replacing it with `order(:id).pluck(:id)` adds an `ORDER BY` clause and
so guarantees the order of the elements.
2019-04-03 21:21:11 +02:00
decabeza
91be3cf775 Fix more hound warnings 2019-03-27 15:22:14 +01:00
decabeza
eda6ea7f12 Merge branch 'master' into dashboard 2019-03-26 16:45:48 +01:00
Julian Herrero
3ba961a2d7 Use double quotes in models 2019-03-14 17:25:43 +01:00
Javi Martín
6682121069 Reuse code to set and order by a random seed 2019-02-20 12:10:12 +01:00
Javi Martín
e3ca700e17 Add concerns to set and order by a random seed 2019-02-20 11:51:32 +01:00
Julian Herrero
d76782f150 Make budgets translatable 2019-02-13 11:41:58 +01:00
Julian Nicolas Herrero
0e9fd645e8 Merge pull request #3234 from consul/use_find_instead_of_find_by_id
[Backport] Use find instead of find_by_id
2019-01-30 19:46:22 +01:00
Julian Herrero
3bf2fa1b17 Add method find_by_slug_or_id to Sluggable module
Make it easier to find by slug or id for sluggable models. Will return
nil if resource is not found.
2019-01-25 09:08:28 +01:00
Javi Martín
e73f3bd97a Add progress bars to milestones public view 2019-01-24 17:33:34 +01:00
Javi Martín
eaea95ccfb Add progress bar model 2019-01-18 14:17:12 +01:00