This way we avoid fetching each translation every time it's requested.
This reduces the amount of queries in the development logs and also
makes the test suite faster.
Since data for this model (title and description) is not generated in
CONSUL but by the United Nations, we aren't storing it in the database
but in our YAML translation files.
The reasoning is as follows. Suppose that, a few months after CONSUL
gets SDG support, a new language is added to CONSUL.
With YAML files, getting the texts in the new language would mean
updating CONSUL to include the new language.
But if we store these texts in the database, it means we have to update
the databases of all existing CONSUL installations, either each
installation by themselves (duplicating efforts) or running a rake task
(which we would have to write each time).
So we believe using translations works better in this case.
We're still storing records in the database with the code, so they can
be easily referenced via `has_many` or `has_many :through` associations.
The original devise_security_extension gem has not been maintained for
years. Its last release was version 0.10.0, and wasn't compatible with
Rails 5, and so we were using its master branch.
Since the gem was unmaintained, it was forked as devise-security and the
aforementioned master branch was released as version 0.10.1. This
version wasn't published in Rubygems, though, so we're now using the
first version that was published in Rubygems and had a release
announment [1].
Dependabot will probably open a pull request to upgrade to the latest
version, but for now I'm trying to keep the devise-security gem as
similar as the version we were using to make sure they're compatible,
particularly considering we're monkey-patching some of the modules
provided by this gem.
[1] https://github.com/devise-security/devise-security/releases/tag/v0.11.1
While Rails provides a lot of functionality by default, there's one
missing piece which is present in frameworks like Django or Phoenix: the
so-called "view models", or "components".
It isn't easy to extract methods in a standard Rails view/partial, since
extracting them to a helper will make them available to all views, and
so two helper methods can't have the same name. It's also hard to
organize the code in modules, and due to that it's hard to figure out
where a certain helper method is supposed to be called from.
Furthermore, object-oriented techniques like inheritance can't be
applied, and so in CONSUL customizing views is harder that customizing
models.
Components fix all these issues, and work the way Ruby objects usually
do.
Components are also a pattern whose popularity has increased a lot in
the last few years, with JavaScript frameworks like React using them
heavily. While React's components aren't exactly the same as the
components we're going to use, the concept is really similar.
I've always liked the idea of components. However, there wasn't a stable
gem we could safely use. The most popular gem (cells) hasn't been
maintained for years, and we have to be very careful choosing which gems
CONSUL should depend on.
The view_component gem is maintained by GitHub, which is as a guarantee
of future maintenance as it can be (not counting the Rails core team),
and its usage started growing after RailsConf 2019. While that's
certainly not a huge amount of time, it's not that we're using an
experimental gem either.
There's currently a conflict between view_component and wicked_pdf.
We're adding a monkey-patch with the fix until it's merged in
wicked_pdf.
We can remove the `new_framework_defaults_5_2` file by using Rails 5.2
default options and overwriting the ones we haven't enabled.
We're disabling `use_authenticated_message_encryption` because, even if
we don't use it, some CONSUL installations might be using it, and
enabling this options would make it harder to decrypt existing encrypted
messages.
And we're disabling `cache_versioning` until we verify our cache keeps
working and expires as expected on production environments, particularly
for stats.
This is enabled by default in Rails 5.2 applications.
Note this change will cause all fragment caching to expire. We consider
it acceptable considering the page where caching is most important
(stats) is barely affected by this change, since this change only
affects the view, and the time-consuming operations are cached in the
model.
Comments are actually affected, though, and pages with thousands of
comments might take a few extra seconds to load the first time they're
accessed after this change. We don't think this is going to be an issue
on existing CONSUL installations.
This is the default encryption for cookies in Rails 5.2 applications.
The reason it isn't enabled automatically for existing applications is
these cookies are not compatible with running the application on several
servers when some of them use Rails 4. Since this isn't our case (we
don't support using different versions of CONSUL on different servers),
and existing cookies are still read correctly, we can safely enable it.
We were manually adding forgery protection to all our controllers, but
in Rails 5.2 there's an option (enabled by default for new applications)
which adds this protection to all controllers.
Even if we don't use form_with, it makes sense to configure it to behave
the same way form_for does.
This is the default option in Rails 5.2 applications. IMHO it should
have been the default option for Rails 5.1 too, since generally form
inputs need an ID so they can easily be associated with a label.
All the code in the `bin/` and the `config/` folder has been generated
running `rake app:update`, except the `escape_javascript_fix` file,
which we've removed since the code there is already included in Rails
5.2.
We were checking tho project_id but not the project_key. However, in our
example secrets file we actually include a project_id but not a
project_key, and so new CONSUL installations would crash in production
environments.
Although technically the application doesn't crash if no host is
defined, we're also ignoring the current environment if no host is
defined, since errbit/airbrake is unlikely to work in this scenario.
Since some people hosting errbit might be using it as an internal tool
with a self signed certificate, we need to patch Airbrake so it accepts
these certificates.
With Errbit, you can set up your own server and host the information
regarding your exceptions there. You can also hire Airbrake's hosting
services or easily setup Errbit on Heroku.
We're still including the rollbar gem so we don't harm CONSUL users who
are using rollbar.
Note Errbit requires an old version of Airbrake which forced users to
configure the gem. So we're adding the current environtment to
`ignore_environments` when the project id isn't defined; this way the
application won't crash in this case.
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.
Using `pluck("DISTINCT")` was raising a warning in Rails 5.2:
DEPRECATION WARNING: Dangerous query method (method whose arguments are
used as raw SQL) called with non-attribute argument(s): "DISTINCT
taggings.tag_id". 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().
Since there was only one other use of distinct, I've decided to change
both of them in the same commit, even if the second one wasn't raising a
warning.
These columns were causing Rails 5.2 to throw a warning when ordering by
them, as if they weren't valid column names:
DEPRECATION WARNING: Dangerous query method (method whose arguments are
used as raw SQL) called with non-attribute argument(s):
:"budget/investments_count". 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 change also makes their names consistent with the rest of our
tables and columns.
Rails 5.2 crashes in the `db:create` task because it tries to run the
`after_initialize` block before the database is created.
The easiest way to solve it is to move the code out of the initializer
and calculate the API type definitions on demand. Note results are still
cached using a class instance variable (not to be confused with a class
variable), and so once definitions are obtained, they will remain
constant until the application is restarted, even in the development
environment.
Recent versions introduce the `Layout/SpaceAroundMethodCallOperator`,
which we are going to use. We aren't upgrading to the latest rubocop
version because it conflicts with the version of Capybara we're using
and because it isn't supported by Hound.
Some rules have been renamed:
Layout/IndentAssignment is now Layout/AssignmentIndentation
Layout/IndentHeredoc is now Layout/HeredocIndentation
Layout/LeadingBlankLines is now Layout/LeadingEmptyLines
Layout/Tab is now Layout/IndentationStyle
Layout/TrailingBlankLines is now Layout/TrailingEmptyLines
Lint/StringConversionInInterpolation is now Lint/RedundantStringCoercion
Metrics/LineLength is now Layout/LineLength
Note after upgrading we get a new "offense" in the `StartWith` rule, so
we're changing the code in order to fix it.
These routes are solved in a different way because of an inconsistency:
we define `groups` and `budget_investments`; we should either use the
`budget_` prefix in all places or remove it everywhere.
We can now share code using `polymorphic_path` even with these models.
In the past, we couldn't use `polymorphic_path` in many places. For
instance, `polymorphic_path(budget, investment)` would return
`budget_budget_investment_path`, while in our routes we had defined
`budget_investment_path`.
With the `resolve` method, introduced in Rails 5.1, we can use symbols
to define we want it to use `investment` instead of `budget_investment`.
It also works with nested resources, so now we can write
`polymorphic_path(investment)`.
This makes the code for `resource_hierarchy_for` almost impossible to
understand. I reached this result after having a look at the internals
of the `resolve` method in order to get its results and then remove the
symbols we include.
Note using this method will not make admin routes compatible with
`polymorphic_path`. Quoting from the Rails documentation:
> This custom behavior only applies to simple polymorphic URLs where a
> single model instance is passed and not more complicated forms, e.g:
> [example showing admin routes won't work]
Also note that now the `admin_polymorphic_path` method will not work for
every model due to inconsistencies in our admin routes. For instance, we
define `groups` and `budget_investments`; we should either use the
`budget_` prefix in all places or remove it everywhere. Right now the
code only works for items with the prefix; it isn't a big deal because
we never call it with an item without the prefix.
Finally, for unknown reasons some routing tests fail if we use
`polymorphic_path`, so we need to redefine that method in those tests
and force the `only_path: true` option.
This plugin provides more control over tables and solves a JS error thrown
when user clicks on "Cell properties" ckeditor feature.
https://ckeditor.com/cke4/addon/tabletools
All of these plugins are not used anywhere.
Change introduced at ckeditor initializer will ommit unneeded
precompilation of plugins assets on production environments.
Change introduced at ckeditor config file adresses the problem with assets
pipeline fallback on testing environments described here: #2711. Now plugins
that are explicitly disabled will not be precomiled when running ckeditor
javascript enabled feature specs.
While this is not a secret and in theory should be in a file under
version control, currently the CONSUL installer disables delayed jobs by
default, meaning we were keeping two versions of the delayed jobs
configuration file, and some existing configurations have their settings
defined in a file in capistrano's `shared` folder.
So we're moving existing settings to the secrets file.
The new version of CKEditor loads the balloonpanel and balloontoolbar
plugins. Even if we don't need them, I haven't found a way to prevent
them from loading, meaning we have to precompile them.
This version solves a security issue:
https://ckeditor.com/cke4/release/CKEditor-4.11.0
Note this version adds a `ckeditor/samples` folder, which is
automatically added to the application's assets manifest even if we
remove all CKEditor references in our application. One of the files in
that folder makes ExecJS raise a syntax error, causing every page to
raise a 500 error.
The `and` and `or` keywords are not equivalent to `&&` and `||` and its
use is counterintuitive. Here's an example
```
good = true && false # good if false
bad = true and false # bad is true
```
The reason is `and` and `or` are control flow operators. So the code:
```
bad = true and false
```
Is equivalent to:
```
if bad = true
false
end
```
We were inconsistent on this one. I consider it particularly useful when
a method starts with a `return` statement.
In other cases, we probably shouldn't have a guard rule in the middle of
a method in any case, but that's a different refactoring.
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
We were already using `find_by` most of the time.
Since there are false positives related to our `find_by_slug_or_id!` and
`find_by_manger_login` methods, which cannot be replaced with `find_by`,
I'm adding it indicating the "refactor" severity.
This will be the default behaviour in Rails 5.1, and it's a much better
approach.
I've checked the code and luckily there doesn't seem to be a single
place where we could accidentally stop the callback chain by returning
false in (for example) a `before_save` callback.