This partial was going to get too complex since in some places we've got
different texts, different URLs or different confirmation messages.
While we should probably try to be more consistent and that would make
the partial work in most cases, there'll always be some exceptions, and
using a partial (with, perhaps, some helper methods) will become messy
really quickly.
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 find the booth through the booth assignment, so we don't need to
pass it in the URL.
Since the parameter is in the URL and not sent through a form, we can
also use `params[:poll_id]` directly, and so we can reuse the
`load_poll` method.
We were getting a deprecation message in Rails 5.2:
> The success? predicate is deprecated and will be removed in Rails 6.0.
> Please use successful? as provided by Rack::Response::Helpers.
We aren't using ActiveStorage, but Rails was including its routes
anyway.
In Rails 6.1 there will be an option to disable these routes [1], but
for now we're changing the line requiring "rails/all" to the values
generated by a new Rails application with the --skip-active-storage
flag.
[1] https://github.com/rails/rails/commit/3cf65bcb8
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.
Rails 5.2 is raising a warning in some places:
DEPRECATION WARNING: Dangerous query method (method whose arguments are
used as raw SQL) called with non-attribute argument(s). 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().
IMHO this warning is simply wrong, since we're using known PostgreSQL
functions like LOWER() or RANDOM(). AFAIK this code works without warnings
in Rails 6.0 [1][2]
However, since the warning is annoying, we need to take measures so our
logs are clean.
[1] https://github.com/rails/rails/commit/6c82b6c99d
[2] https://github.com/rails/rails/commit/64d8c54e16
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're not replacing `form_for` with `form_with` for now, and even if we
did, most of our forms are not remote, so making them remote by default
would be inconvenient.
This is the default in Rails 5.1 applications. If we want to use an
asset in the public folder, we need to add the `public_folder: true`
option, making it clear that we don't expect the asset to be in the
asset pipeline.
Since we don't use `asset_path` to reference assets in the public
folder, we can safely disable the `unknown_asset_fallback` option.
This option was added by Rails 4 new application generator. However, the
`assets.digest` option is set to true by default, and recent Rails
versions don't even add this option to the environment files.
Changing it would mean reviewing and changing all our existing models,
and some of them might be tricky (like our Document and Image models,
which only validate certain associations in some cases), so we're
keeping it the way it's been until now.
The default options (which apply when `force_ssl` is set, which is the
default in CONSUL) are `{ hsts: { subdomains: true } }`, which means we
tell browsers to apply our SSL settings to subdomains as well [1].
CONSUL installations implementing multitenancy with subdomains will
benefit from this change.
[1] https://api.rubyonrails.org/classes/ActionDispatch/SSL.html
Quoting the Rails DateAndTime::Compatibility module:
> With Ruby 2.4+ the default for +to_time+ changed from
> converting to the local system time, to preserving the offset
> of the receiver. For backwards compatibility we're overriding
> this behavior
We don't need backwards compatibility in our application because we
aren't converting any time objects to the local system timezone but use
the application timezone all the time instead.
This is the default in Rails 5 applications.
This option is not enabled by default in existing applications because
it would break applications running on several domains and doing POST
requests between them or running a reverse proxy that rewrites the Host
header. Since those aren't our cases, it's safe to enable it.
This is the default for new Rails application, and adds an extra layer
of security since now the token will only be valid for its action, and
so attackers managing to change the form action will not do any harm
since the CSRF token will not work for the attackers' action.
Note that we've had InvalidAuthenticityToken exceptions for years; if we
keep getting them, chances are this change is *not* related.
The goal here is to have a notion on what the defaults are in a Rails 5
application, know why our application is working in a different way
(it's because these defaults aren't loaded in an application which was
originally developed using Rails 4), and have an explicit list of things
we are overwriting.
Furthermore, running the `app:update` rake task to upgrade to Rails 5.2
will by default add the line loading default options for Rails 5.0, so
by adopting those default options we prevent accidental mistakes when
upgrading.
We'll have to review these items and see which ones can be changed to
their default values for Rails 5 applications.