When clicking the browser's back button, browsers usually don't reload
the page but show a cached version of the page.
Turbolinks takes this one step further. When clicking on a link to a
page that's already cached, turbolinks displays the cached version of
the page and then it reloads it.
I don't really like this behavior but, since it affects the whole
application and we're about to release a patch version :), for now we're
keeping it this way in the development and production environments.
In the test environment, however, we're disabling these previews because
they might lead to requests leaking between tests.
For example, a test that visits the investments index, then goes to
"check my votes", then clicks on "Go back" and finishes by checking some
content on this page will result in those checks being done against the
cached version of the page. If these checks pass before turbolinks
reloads the page, the "Go back" request will finish during the test that
runs immediately after this one, resulting in unpredictable results.
Disabling the previews solves the issue.
Since the PR "Do not use third-party cookies in embedded videos #5548", the logic from
"embed_videos_helper" was extracted to the "embedded_video_component" and the
"videoable" model concern.
However, during this refactor, the "regex" method, which uses record.class:: to handle
video embeds, was left inaccessible for Legislation Proposals.
This commit fixes the issue by including the concern in the Legislation Proposal model.
In rubocop-rails 2.26.0, the Rails/CompactBlank rule was modified to handle
cases where select(&:present?) is used. After identifying three occurrences
in our code, we've decided to apply this rule as it encourages the use of the
more efficient and clearer method, compact_blank.
By using compact_blank, we improve code clarity and performance, as this method performs the same operation but in a more optimized way.
In rubocop-rails 2.26.0, support was added for Rails 7 syntax in the
Rails/EnumHash rule. We took this opportunity to ensure consistency
by converting all enums to hash with integer values. This format minimizes
the risk of data consistency issues in the database when adding new values.
This rule was added in rubocop-rails 2.26.0. Applying it allows
us to anticipate the deprecation of the current enum syntax
using keyword arguments, which is set to be removed in Rails
8.0, as mentioned in the rule's own documentation:
https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsenumsyntax
This rule was introduced in RuboCop 0.67.2, but now after seeing a fix in version 1.65.1,
we have decided to add it. The reason for adding it is to ensure consistency in how we
reference exceptions throughout the project, by following a standard naming convention
for exception variables.
This rule was introduced in RuboCop 1.53.0. After adding the
Style/RedundantRegexpCharacterClass rule in the previous commit,
RuboCop started detecting redundant regular expression arguments.
Therefore, we apply this rule to remove them and prevent future
occurrences.
This rule was introduced in RuboCop 0.93.0, but now after seeing a fix in version 1.65,
we have decided to add it. The reason for adding it is to simplify our regular
expressions. This enforcement will help us maintain better regular expression
practices across the project.
We accidentally removed the code for maximum complexity in commit
c984e666f. As mentioned in the documentation:
> The main risk factor is multiple collections of resources being
> requested in the same query.
We reject these requests by limiting the complexity.
The `max_complexity` option depends on the page size being set. Without
it, we get an error:
```
Can't calculate complexity for User.public_debates, no `first:`,
`last:`, `max_page_size` or `default_max_page_size`
```
So we're also adding a default max page size.
Note that the documentation mentioned that the default page size was 25.
However, before commit c984e666f, we were using a page size of 50 in
some cases. We're going with the one mentioned in the documentation
since we don't fully understand the old code.
We accidentally removed this code in commit c984e666f. As mentioned in
our GraphQL documentation, limiting the depth of the queries helps
against DoS attacks.
When returning a collection of records in the API, we were making sure
we only returned public ones. However, when returning individual
records, we were not checking that.
In practice, this wasn't a big issue, since most `public_for_api`
methods return all records, but it could affect Consul Democracy
installations which might have customized their `public_for_api` method.
The only exception was the `budget` method, since it was returning
budgets that were still in drafting.
- added 2 new types
- modified the models to get data through graphQL
- modified the corresponding spec
- also testing that hidden comments do not show up
- modified comments specs bc now it returns comments on budget
investments
Note that, while it doesn't really affect the way the application
behaves (as long as the JavaScript code doesn't rely on the order it's
loaded) we're requiring `app/assets/javascripts/custom.js` after
requiring any files in the `app/assets/javascripts/custom/` folder. This
is done for consistency, since we load the content of
`app/assets/javascripts/application.js` after requiring everything else.
It was a bit strange to leave the end date blank and have a message
associated with the start date, so we're using presence validations
instead.
For the range validation, we're using the comparison validator included
in Rails 7.0.
The `validates_comparison_of` method was added in Rails 7.0.
We aren't changing the `date_range` validation in polls yet because it's
a bit complex; we'll do it in the next commit.
While the `minimum` and `maximum` methods have been available for a long
time for ActiveRecord relations, Rails 7.0 has added these methods for
enumerables as well.
This means that the `start_date` and `end_date` methods in the
ShiftsHelper can use `minimum` and `maximum` no matter whether they
receive an ActiveRecord relation or an array of polls (I think the
latter never happens, though, but I'm not 100% sure).
This method was added in Rails 7.0 and makes the code slihgtly more
readable.
The downside is that it generates two queries instead of one, so it
might generate some confusion when debugging SQL queries. Its impact on
performance is probably negligible.
This method was introduced in Rails 7.0, and thanks to it we can
simplify the code that gets the translations in order.
We tried to use this method to simplify the `Randomizable` concern as
well. However, we found out that, when ordering tens of thousands of
records, the query could take several minutes, so we aren't using it in
this case. Using it for translation fallbacks is OK, since there's a
good chance we're never going to have tens of thousands of available
locales.
Note that automated security tools reported a false positive related to
SQL Injection due to the way we used `LEFT JOIN`, so now we get one less
false positive in these reports.
We hadn't added this rule before because there was no such rule in
scss-lint. Instead, we were following it without a linter, and so we
unintentionally broke it sometimes.
But now we're using Stylelint, so we can add the rule and let the linter
check we're still following it.
This rule was added in rubocop 1.64.0.
For clarity, in order to make it obvious that we're modifying the object
we received, we're excluding the Ahoy initializer, whose code was copied
from the Ahoy documentation.
We're also changing the `Types::BaseObject` class so we don't use a
variable with the same name as the parameter and we don't get a false
positive for this rule.
These cases aren't covered by the `Rails/WhereRange` rubocop rule, but
IMHO using ranges makes them more consistent. Besides, they generate SQL
which is more consistent with what Rails usually generates. For example,
`Poll.where("starts_at <= :time and ends_at >= :time", time:
Time.current)` generates:
```
SELECT \"polls\".\"id\", (...) WHERE \"polls\".\"hidden_at\" IS NULL AND
(starts_at <= '2024-07-(...)' and ends_at >= '2024-07-(...)')
```
And `Poll.where(starts_at: ..Time.current, ends_at: Time.current..)`
generates:
```
SELECT \"polls\".\"id\", (...) WHERE \"polls\".\"hidden_at\" IS NULL AND
\"polls\".\"starts_at\" <= '2024-07-(...)' AND \"polls\".\"ends_at\" >=
'2024-07-(...)'"
```
Note that the `not_archived` scope in proposals slightly changes, since
we were using `>` and now we use the equivalent of `>=`. However, since
the `created_at` field is a time, this will only mean that a proposal
will be archived about one microsecond later.
For consistency, we're also changing the `archived` scope, so a proposal
is never archived and not archived at the same time (not even for a
microsecond).
This rule was added in rubocop-rails 2.25.0. Applying it allows us to
simplify the code a little bit. For example, now there's no need to
specify the `proposals` table in proposal scopes, which was actually
causing a bug in the `Legislation::Proposal` model, which was using the
`proposals` table instead of the `legislation_proposals` table (but,
since we don't use this scope, it didn't affect the application).
Until now, we've stored the text of the answer somebody replied to. The
idea was to handle the scenarios where the user voters for an option but
then that option is deleted and restored, or the texts of the options
are accidentally edited and so the option "Yes" is now "Now" and vice
versa.
However, since commit 3a6e99cb8, options can no longer be edited once
the poll starts, so there's no risk of the option changing once somebody
has voted.
This means we can now store the ID of the option that has been voted.
That'll also help us deal with a bug introduced int 673ec075e, since
answers in different locales are not counted as the same answer. Note we
aren't dealing with this bug right now.
We're still keeping (and storing) the answer as well. There are two
reasons for that.
First, we might add an "open answer" type of questions in the future and
use this column for it.
Second, we've still got logic depending on the answer, and we need to be
careful when changing it because there are existing installations where
the answer is present but the option_id is not.
Note that we're using `dependent: nullify`. The reasoning is that, since
we're storing both the option_id and the answer text, we can still use
the answer text when removing the option. In practice, this won't matter
much, though, since we've got a validation rule that makes it impossible
to destroy options once the poll has started.
Also note we're still allowing duplicate records when the option is nil.
We need to do that until we've removed every duplicate record in the
database.
It was confusing to have the action to create an answer in
`QuestionsController#answer` while the action to destroy it was
`AnswersController#destroy`.
The routes for poll questions were accidentally deleted in commit
5bb831e959 when deleting the `:show` action, and restored in commit
9871503c5e. However, the deleted code was:
```
resources :questions, only: [:show], controller: 'polls/questions' (...)
```
While the restored code was:
```
resources :questions, controller: 'polls/questions' (...)
```
Meaning we forgot to add the `only: []` option when restoring the
routes.
We also forgot to remove the `before_action` code when deleting the
`:show` action, so we're removing it now.
Note that, when taking votes from an erased user, since poll answers
don't belong to poll voters, we were not migrating them in the
`take_votes_from` method (and we aren't migrating them now either).
This call was added in commit 81f65f1ac, and the test for its need was
added in commit cb1542874. However, both the test and the helper method
relying on the `touch` call were removed in commit f90d0d9c4.
We were checking we didn't have more votes than allowed in the case of
questions with multiple answers, but we weren't checking it in the case
of questions with a single answer. This made it possible to create more
than one answer to the same question. This could happen because the
method `find_or_initialize_user_answer` might initialize two answers in
different threads, due to a race condition.
Most existing Consul Democracy installations will have changed their
`config.i18n.available_locales` option so only a few locales are
available. In many cases, only one locale will be available. In these
cases, rendering a form that only offers one option is useless.
We've considered adding a text in this case mentioning that, in order to
enable more languages, they need to configure their
`config.i18n.available_locales`. However, we haven't done it for two
reasons.
First, if they've changed the available locales to just one, there's a
good chance they aren't interested at all in configuring the locales.
And, second, if there's only one available locale, administrators will
learn to ignore the "languages" link, so they won't realize that locales
can be configured if developers change the available locales. If we hide
the link, on the other hand, they will notice that locales can now be
configured once developers change the available locales.
Note we're still allowing access by entering the URL. This is harmless,
though, since people accessing it this way will see a form with only one
possible option and won't be able to modify anything.
We were using `authorize_resource`, passing it an unnamed parameter.
When that happens, CanCanCan only checks permissions to read that
resource. But, in this case, we want to check the permission to update
that resource before the `update` action.
Most of the time, it doesn't really matter, but, for example, in our
demo we're going to restrict the locales configuration so locales cannot
be updated on the main tenant (but they can be updated on other
tenants).
In commit 9329e4b6e, `try` was added because there was a case where this
partial was rendered and the `current_booth` method didn't exist.
However, that's no longer the case since commit d5c7858f6. Since then,
this partial is only rendered in the officing section, where the
`current_booth` method is defined.
So we can use the safe navigation operator instead of `try`.
In commit 35659d441, we started using an <svg> tag instead of an <img>
tag to render avatars. That meant that the `vertical-align: middle` rule
we've got for images was no longer being applied.
So we're adding it back.
The only places where this icon wasn't rendered correctly were "my
account" and the show action in the users controller. The comments were
not affected because we've got a `float: left` rule for the
`comment-avatar svg` selector, which causes the browser to ignore the
value of the `vertical-align` propertly, and the avatars showing author
information were not affected because the `.author-photo` selector
already had a `vertical-align` rule.