Up until now, we were assuming the voter was valid, but were not raising
an exception if it wasn't. And in the user interface everything seemed
to be working properly.
We were having this issue when skipping verification, when there could
be voters without a document number, which would be considered invalid.
Raising an exception when failing to save the voter and making sure the
answer and the voter are saved inside a transaction solves the problem.
The `$()` function is a shortcut for `$(document).ready()`, and we were
attaching events to `$(document).ready()` inside the `$()` function.
In a similar way, we were handling the `page:load` and `ajax:complete`
events inside the `$()` function. But when those events trigger, the DOM
is already ready.
Besides, we don't have to wait for the DOM to be ready before attaching
events to the `document` element. Quoting jQuery's `.on()`
documentation:
> The document element is available in the head of the document before
> loading any other HTML, so it is safe to attach events there without
> waiting for the document to be ready.
Co-Authored-By: Senén Rodero Rodríguez <senenrodero@gmail.com>
In the past we had huge problems trying to make it work with Turbolinks.
However, after updating foundation-rails in commit 58071fd6, these hacks
aren't necessary anymore.
We're adding a test for the scenario of visiting a page using
Turbolinks, which was missing, so we're sure we aren't breaking
anything.
Note the sticky will still not work after using the browser back button.
We haven't been able to make it work with turbolinks-classic; we'll fix
this issue when upgrading turbolinks.
Its known that initializing a map when it is inside a hidden element
wont work when hidden element is shown, so its makes sense to
avoid initialization of hidden maps.
When a map lives within a hidden layer we need to initialize the
map after the event of showing that hidden layer, in our case when
admin settings tab is shown.
TableSortable and Sortable javascripts were using the same CSS
class name to define completely different and separated
behaviours causing unexpected errors. Now `sortable.js` script
will use `.sortable` class and `table_sortable.js` will use
`.table-sortable` instead.
We were displaying two progress bars for the same thing, and hiding one
of them.
Displaying just one of them and readjusting the styles accordingly is a
bit more intuitive IMHO.
We're also getting the text inside the progress bar out of it; its
purpose inside an element with the `progressbar` role is to provide the
same information as the progress bar (which we aren't exactly doing,
although it could be argued that we do), and in order to be accessible
we should provide the same text in the `aria-valuetext` field, which we
aren't doing. This also simplifies our CSS, which was working because we
defined a padding which covered the height of the hidden extra progress
bar and would have needed quite a few changes if we kept just one
progress bar with text inside it. We can also remove a few CSS rules
which we added to override foundation's rules for the
`progress-meter-text` class.
We were setting it to 0, and so screen reader users might be confused by
it.
The easiest way to reuse the code and using it for both this attribute
and the width of the progress bar is to move this method to the voting
style, just like the other methods used in this view.
Note the progressbar ARIA role might not be right, since this isn't a
task which is "progressing", but an indicator of the amount spent and
amount available, which is exactly what the <meter> HTML5 tag was
designed for.
We might use a <meter> tag in the future. For now, I'm leaving it as it
is because I'm not certain about how well <meter> is supported in
accessibility tools, and because it's definitely not supported in
Internet Explorer 11, which we haven't officially dropped support for.
We were rendering an individual ballot, and then rendering all ballots
(including the already rendered one). So we can skip the first part, as
pointed out by microweb10 in the comments of pull request 3036.
In the Knapsack voting style, we can't add an investment if its cost is
greater than the money we've got left, but in other voting styles money
might not be the issue.
So we're introducing the term "resources" and adapting the code
accordingly.
We're passing the amount as a paramenter to the "remaining" text, so it
makes sense to pass it to the "amount spent" text as well.
Here we're also changing the I18n key to the text saying users can
change their vote, so it's easier to note the text is about changing
their vote, and not about the projects they have voted so far.
Since we're going to introduce a new voting style which will not be
based on money, we're extracting the logic specific to the current
voting style to a new class.
This way adding new voting styles will be easier.
The heading is used with `find_by_slug_or_id`, which raises an exception
if it isn't found, so executing `@heading.group` after it does not need
the safe navigation operator.
We were using the same logic twice.
I've moved the logic to the Ballot model, which to me is a more natural
place to calculate whether there's enough money left than the Investment
model. After all, the remaining money is in the ballot, and not in the
investment.
The `refresh_ballots` partial ignores the `investment` parameter
completely; instead, it iterates over the investments in the
`@investments` instance variable.
One method was calling `reason_for_not_being_ballotable_by` passing just
one parameter instead of two.
The other method was calling the method `amount_spent`, which does not
exist in the Budget class.
So both methods would make the application crash if they were called.
Luckily, they aren't, so the application doesn't crash.
We were writing the same code twice, with the only difference being the
text "Sign up" in the sign_up action, and "Sign in" in the sign_in
action.
Note we're renaming the `omniauth.info_*` I18n keys so we don't need to
add new exceptions to the `ignore_unused` list, and so it's consistent
with all the other keys under the `omniauth` key.
When a legislation process is deleted, everything related will be
deleted, including the answers. This `dependent: :destroy` was causing
that users accounts were being accidentally deleted.
The test wasn't working when postgres used the English dictionary
because in English the word "what" was ignored (or, at least, not given
enough relevance) while searching. When we wrote the test, it passed
because back then we always used the Spanish dictionary. However, when
we switched to a dictionary based on the default locale (in commit
d99875cd), we had to force this test to keep using the Spanish
dictionary.
Using the Spanish dictionary in a test where all texts are in English is
strange to say the least ;). So here we're making the test a bit easier
to understand.
Since now we're only using the `:spanish_search` tag in one test, I've
decided to remove it and simply add it to that test's setup.
Using pg_search 2.0.1 with Rails 5.2 results in deprecation warnings:
DEPRECATION WARNING: Dangerous query method (method whose arguments used
as raw SQL) called with non-attribute argument(s):
"pg_search_978c2f8941354cf552831b.rank DESC, \"tags\".\"id\" ASC".
Non-attribute arguments will be disallowed in Rails 6.0. This method
should not be called with user-provided values, such as request
parameters or model attributes. Known-safe values can be passed by
wrapping them in Arel.sql().
We're not upgrading to the latest pg_search because it only supports
ActiveRecord >= 5.2.
In Ruby 5.2, we get a warning when using the "RANDOM()" function:
DEPRECATION WARNING: Dangerous query method (method whose arguments are
used as raw SQL) called with non-attribute argument(s): "RANDOM()".
Non-attribute arguments will be disallowed in Rails 6.0. This method
should not be called with user-provided values, such as request
parameters or model attributes. Known-safe values can be passed by
wrapping them in Arel.sql().
This warning doesn't make much sense, though, since RANDOM() is a common
function which is not dangerous at all. However, since the warning is
annoying, we'll probably have to find a way to deal with it.
So I'm extracting all our RANDOM() usages into a method. This way we'll
only have to change one method to avoid this warning.
I've chosen `sample` because it's similar to Ruby's Array#sample, and
because `order_by_random` would be confusing if we consider we already
have a method called `sort_by_random`.
We were getting a deprecation message in Rails 5.2:
The missing? predicate is deprecated and will be removed in Rails 6.0.
Please use not_found? as provided by Rack::Response::Helpers
With two concurrent requests, it's possible to create two ballot lines
when only one of them should be created.
The reason is the code validating the line is not thread safe:
```
if ballot.amount_available(investment.heading) < investment.price.to_i
errors.add(:money, "insufficient funds")
end
```
If the second request executes this code after the first request has
executed it but before the first request has saved the record to the
database, both records will pass this validation and both will be saved
to the database.
So we need to introduce a lock. Now when the second request tries to
lock the ballot, it finds it's already locked by the first request, and
will wait for the transaction of the first request to finish before
checking whether there are sufficient funds.
Note we need to disable transactions during the test; otherwise the
second thread will wait for the first one to finish.
Also note that we need to update a couple of tests because records are
reloaded when they're locked.
In one case, reloading the ballot causes `ballot.user` to be `nil`,
since the user is hidden. So we hide the user after creating all its
associated records (which is the scenario that would take place in real
life).
In the other case, reloading the ballot causes `ballot.user` to reload
as well. So we need to reload the user object used in the test too so it
gets the updates done on `ballot.user`.
I haven't been able to reproduce this behavior in a system test. The
following test works with Rails 5.0, but it stopped working when we
moved to system tests in commit 9427f014. After that commit, for reasons
I haven't been able to debug (reintroducing truncation with
DatabaseClaner didn't seem to affect this test, and neither did
increasing the number of threads in Puma), the two AJAX requests
executed here are no longer simultaneous; the second request waits for
the first one to finish.
scenario "Race conditions with simultaneous requests", :js do
allow_any_instance_of(Budget::Ballot::Line).to receive(:check_sufficient_funds) do |object|
allow(object).to receive(:check_sufficient_funds).and_call_original
object.check_sufficient_funds
sleep 0.3
end
["First", "Second"].each do |title|
create(:budget_investment, :selected,
heading: california,
price: california.price,
title: title
)
end
login_as(user)
visit budget_investments_path(budget, heading_id: california.id)
within(".budget-investment", text: "First") { click_link "Vote" }
within(".budget-investment", text: "Second") { click_link "Vote" }
expect(page).to have_link "Remove vote"
expect(Budget::Ballot::Line.count).to eq 1
end