Note that, for everything to work consistently, we need to make sure
that the default locale is one of the available locales.
Also note that we aren't overwriting the `#save ` method set by
globalize. I didn't feel too comfortable changing a monkey-patch which
ideally shouldn't be there in the first place, I haven't found a case
where `Globalize.locale` is `nil` (since it defaults to `I18n.locale`,
which should never be `nil`), so using `I18n.default_locale` probably
doesn't affect us.
Note that, currently, we take these settings from the database but we
don't provide a way to edit them through the admin interface, so the
locales must be manually introduced through a Rails console.
While we did consider using a comma-separated list, we're using spaces
in order to be consistent with the way we store the allowed content
types settings.
The `enabled_locales` nomenclature, which contrasts with
`available_locales`, is probably subconsciously based on similar
patterns like the one Nginx uses to enable sites.
Note that we aren't using `Setting.enabled_locales` in the globalize
initializer when setting the fallbacks. This means the following test
(which we could add to the shared globalizable examples) would fail:
```
it "Falls back to an enabled locale if the fallback is not enabled" do
Setting["locales.default"] = "en"
Setting["locales.enabled"] = "fr en"
allow(I18n.fallbacks).to receive(:[]).and_return([:fr, :es])
Globalize.set_fallbacks_to_all_available_locales
I18n.with_locale(:fr) do
expect(record.send(attribute)).to eq "In English"
end
end
```
The reason is that the code making this test pass could be:
```
def Globalize.set_fallbacks_to_all_available_locales
Globalize.fallbacks = I18n.available_locales.index_with do |locale|
((I18n.fallbacks[locale] & Setting.enabled_locales) + Setting.enabled_locales).uniq
end
end
```
However, this would make it impossible to run `rake db:migrate` on new
applications because the initializer would try to load the `Setting`
model but the `settings` table wouldn't exist at that point.
Besides, this is a really rare case that IMHO we don't need to support.
For this scenario, an installation would have to enable a locale, create
records with contents in that locale, then disable that locale and have
that locale as a fallback for a language where content for that record
wasn't created. If that happened, it would be solved by creating content
for that record in every enabled language.
While running the `dev_seed` twice, as we do in the tests, we were
getting the following warnings:
```
db/dev_seeds/proposals.rb:1: warning: already initialized constant
IMAGE_FILES
db/dev_seeds/budgets.rb:1: warning: already initialized constant
INVESTMENT_IMAGE_FILES
```
So we're extracting a method which allows us to use local variables
while removing duplication.
We had this warning with every version of Ruby, not just Ruby 2.7, but
since we're getting rid of all the warnings, we're taking care of this
one as well.
Until now, running `db:dev_seed` created development data for the
default tenant but it was impossible to create this data for other
tenants.
Now the tenant can be provided as a parameter.
Note that, in order to be able to execute this task twice while running
the tests, we need to use `load` instead of `require_relative`, since
`require_relative` doesn't load the file again if it's already loaded.
Also note that having two optional parameters in a rake task results in
a cumbersome syntax to execute it. To avoid this, we're simply removing
the `print_log` parameter, which was used mainly for the test
environment. Now we use a different logic to get the same result.
From now on it won't be possible to pass the option to avoid the log in
the development environment. I don't know a developer who's ever used
this option, though, and it can always be done using `> /dev/null`.
When running this task we truncate all tables; however, doing so doesn't
execute the `after_destroy` callback which drops the generated schema.
That meant we could run into a situation where there are schemas in the
database with no associated tenant, leading to data inconsistencies.
So we're now destroying the tenants (alongside their schemas) before
truncating the rest of the database tables.
Performance tests show both methods of truncating the database take
about the same time, so we can remove one dependency and we don't lose
anything in the process.
Some developers work on CONSUL installations where Spanish and/or
English aren't part of the available locales. In those cases, the
`dev_seed` task was crashing because we were using attributes like
`name_en` and `name_es`.
So we're using attributes for random locales instead.
We're using a proc so we don't have code like this all over the place:
random_locales.map do |locale|
I18n.with_locale(locale) do
phase.name = I18n.t("budgets.phase.#{phase.kind}")
phase.save!
end
end
This would make the code harder to read and would execute a `save!` once
per locale, which would make the task much slower.
We could also avoid the procs writing something like:
def random_locales_attributes(**attribute_names_with_values)
random_locales.each_with_object({}) do |locale, attributes|
I18n.with_locale(locale) do
attribute_names_with_values.each do |attribute_name, (i18n_key, i18n_args)|
value = I18n.t(i18n_key, (i18n_args || {}).merge(language: I18n.t("i18n.language.name")))
attributes["#{attribute_name}_#{locale.to_s.underscore}"] = value
end
end
end
end
And calling the method with with:
random_locales_attributes(name: ["seeds.budgets.name", year: Date.current.year - 1])
However, this code would also be different that what we usually do, we'd
have to apply some magic to pass the `language:` parameter, and the
strings wouldn't be recognized by i18n-tasks, so we aren't sure we're
really gaining anything.
These locales are officially maintained by CONSUL developers, so we're
using them when available.
This way we'll be able to use `random_locales` in places where we're
manually using English and Spanish, giving support to other locales
while maintaining compatibility with the current version.
The db:dev_seed rake logs info as it progresses as information for the
developer. But that's not needed when ran from its tests file, and it
bloats the travis/rspec output with unnecessary information.
Now the task will always log info unless the rake task receives an
optional argument.
Why:
Its a really huge script, and conflicts are hard to resolve on forks,
with indivudal scripts its easier to make custom changes.
How:
Following @mariacheca example using require_relative and a file under
the db/dev_seeds/ folder
During a Participatory Budget, some users are getting confused and
creating a proposal instead of a budget investment. This intermediate
page should help them create investments
Adding a feature flag just in case other forks don’t need this feature
and setting seeds and dev_seeds for appropriate initial setup