In the form of creating a new investment was hiding the name of the
group if it had only one heading, but could be confusing to users if
there are, for example, five different groups of one heading.
The solution:
- If the budget has one group and one heading, the heading selector is
hidden.
- If the budget has one group and more than one heading, the group name
is hidden.
- If the budget has more than one group, the group name appears
regardless of the number of headings.
- Allow to define a link (text and url) on budget form for render on the budget
header.
- Improve styles
Co-authored-by: Senén Rodero Rodríguez <senenrodero@gmail.com>
So now there's no need to edit each phase individually to enable/disable
them.
We aren't doing the same thing in the form to edit a budget because we
aren't sure about possible usability issues. On one hand, in some tables
we automatically update records when we mark a checkbox, so users might
expect that. On the other hand, having a checkbox in the middle of a
form which updates the database automatically is counter-intuitive,
particularly when right below that table there are other checkboxes
which don't update the database until the form is submitted.
So, either way, chances are users would think they've updated the phases
(or kept them intact) while the opposite would be true.
In the form within the wizard to create a budget that problem isn't that
important because there aren't any other fields in the form and it's
pretty intuitive that what users do will have no effect until they press
the "Finish" button.
Co-Authored-By: Julian Nicolas Herrero <microweb10@gmail.com>
In this case, the duration of the budget cannot be determined, and the
application was crashing when trying to do so.
Now we're just returning `nil` as duration.
We don't allow deleting a budget with associated investments. However,
we allow deleting a budget with associated administrators and valuators.
This results in a foreign key violation error:
PG::ForeignKeyViolation: ERROR: update or delete on table "budgets"
violates foreign key constraint "fk_rails_c847a52b1d" on table
"budget_administrators"
Using the `dependent: :destroy` option when defining the relationship,
we remove the association records when removing the budget.
As a bonus, we reduce the number of Rubocop offenses regarding the
`Rails/HasManyOrHasOneDependent` rule. Only 72 to go! :)
Previously the draft mode was a phase of the PB, but that had some
limitations.
Now the phase drafting disappears and therefore the PB can have the
status published or not published (in draft mode).
That will give more flexibility in order to navigate through the
different phases and see how it looks for administrators before
publishing the PB and everybody can see.
By default, the PB is always created in draft mode, so it gives you
the flexibility to adjust and modify anything before publishing it.
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.
When defining abilities, scopes cover more cases because they can be
used to check permissions for a record and to filter a collection. Ruby
blocks can only be used to check permissions for a record.
Note the `Budget::Phase.kind_or_later` name sounds funny, probably
because we use the word "phase" for both an an attribute in the budgets
table and an object associated with the budget, and so naming methods
for a budget phase is a bit tricky.
The current tracking section had a few issues:
* When browsing as an admin, this section becomes useless since no
investments are shown
* Browsing investments in the admin section, you're suddenly redirected
to the tracking section, making navigation confusing
* One test related to the officing dashboard failed due to these changes
and had been commented
* Several views and controller methods were copied from other sections,
leading to duplication and making the code harder to maintain
* Tracking routes were defined for proposals and legislation processes,
but in the tracking section only investments were shown
* Probably many more things, since these issues were detected after only
an hour reviewing and testing the code
So we're removing this untested section before releasing version 1.1. We
might add it back afterwards.
Tags and help links can be edited, but aren't used anywhere. Since we
don't know what the intended behavior was, I'm removing them for now.
My best guess is tags were supposed to be used so investments for a
budget can only be assigned tags present in the budget. Achieving that
behavior wouldn't be a trivial task.
Since budgets now have milestone tags, the name of this method was
confusing and will conflict with the name generated by acts_as_taggable.
Note the new name could be improved too.
We were very inconsistent regarding these rules.
Personally I prefer no empty lines around blocks, clases, etc... as
recommended by the Ruby style guide [1], and they're the default values
in rubocop, so those are the settings I'm applying.
The exception is the `private` access modifier, since we were leaving
empty lines around it most of the time. That's the default rubocop rule
as well. Personally I don't have a strong preference about this one.
[1] https://rubystyle.guide/#empty-lines-around-bodies
In Ruby, the Kernel class defined the `open` method, which is available
for (almost) every object. So creating a scope with the name `open`
generates a warning indicating we are overwriting the existing `open`
method.
While this warning is pretty much harmless and we could ignore it, it
generates a lot of noise in the logs. So I'm "undefining" the method
before generating the scope, so we don't get the warning all the time.
Sanitizing descriptions before saving a record has a few drawbacks:
1. It makes the application rely on data being safe in the database. If
somehow dangerous data enters the database, the application will be
vulnerable to XSS attacks
2. It makes the code complicated
3. It isn't backwards compatible; if we decide to disallow a certain
HTML tag in the future, we'd need to sanitize existing data.
On the other hand, sanitizing the data in the view means we don't need
to triple-check dangerous HTML has already been stripped when we see the
method `auto_link_already_sanitized_html`, since now every time we use
it we sanitize the text in the same line we call this method.
We could also sanitize the data twice, both when saving to the database
and when displaying values in the view. However, doing so wouldn't make
the application safer, since we sanitize text introduced through
textarea fields but we don't sanitize text introduced through input
fields.
Finally, we could also overwrite the `description` method so it
sanitizes the text. But we're already introducing Globalize which
overwrites that method, and overwriting it again is a bit too confusing
in my humble opinion. It can also lead to hard-to-debug behaviour.
As mentioned in the Rails console:
DEPRECATION WARNING: Passing a class to the `class_name` is deprecated
and will raise an ArgumentError in Rails 5.2. It eagerloads more classes
than necessary and potentially creates circular dependencies. Please
pass the class name as a string.
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.
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.
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.0diff-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.
These tests were failing randomly because there is no guarantee
the methods `Budget#email_selected` and `Budget#email_unselected` will
always send the emails in the same order, because `investments.selected`
and `investments.unselected` don't necessarily return the records in the
order they were created.
Ordering by id is certainly not very elegant; however, ordering by
another field like `created_at` is dangerous because the record could be
created at (almost) the exact same time.
Related to issue #2446 and issue #2519.