The current consul GraphQL API has two problems.
1) It uses some unnecessary complicated magic to automatically create
the GraphQL types and querys using an `api.yml` file. This approach
is over-engineered, complex and has no benefits. It's just harder to
understand the code for people which are not familiar with the
project (like me, lol).
2) It uses a deprecated DSL [1] that is soon going to be removed from
`graphql-ruby` completely. We are already seeing deprecation warning
because of this (see References).
There was one problem. I wanted to create the API so that it is fully
backwards compatible with the old one, BUT the old one uses field names
which are directly derived from the ruby code, which results in
snake_case field names - not the GraphQL way. When I'm using the
graphql-ruby Class-based syntax, it automatically creates the fields in
camelCase, which breaks backwards-compatibility.
So I've added deprecated snake_case field names to keep it
backwards-compatible.
[1] https://graphql-ruby.org/schema/class_based_api.html
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.
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
Having exceptions is better than having silent bugs.
There are a few methods I've kept the same way they were.
The `RelatedContentScore#score_with_opposite` method is a bit peculiar:
it creates scores for both itself and the opposite related content,
which means the opposite related content will try to create the same
scores as well.
We've already got a test to check `Budget::Ballot#add_investment` when
creating a line fails ("Edge case voting a non-elegible investment").
Finally, the method `User#send_oauth_confirmation_instructions` doesn't
update the record when the email address isn't already present, leading
to the test "Try to register with the email of an already existing user,
when an unconfirmed email was provided by oauth" fo fail if we raise an
exception for an invalid user. That's because updating a user's email
doesn't update the database automatically, but instead a confirmation
email is sent.
There are also a few false positives for classes which don't have bang
methods (like the GraphQL classes) or destroying attachments.
For these reasons, I'm adding the rule with a "Refactor" severity,
meaning it's a rule we can break if necessary.
These variables can be considered a block, and so removing them doesn't
make the test much harder to undestand.
Sometimes these variables formed the setup, sometimes they formed an
isolated part of the setup, and sometimes they were the part of the test
that made the test different from other tests.
While this is potentially very dangerous because assigning the ID does
not increase the ID sequence, it's safe to do so in tests where we
assign the ID to every record created on a certain table.
Even so, I'd consider it a bad practice which must be used with care. In
this case I'm using it because we look for IDs in the response, and
most tests in this file use literals to compare the response.
This changes makes it possible to remove unused variables while keeping
the test readable.
Since we're obtaining titles and usernames in the response, it's easier
to compare them to titles and usernames we manually set.
Furthermore, this way we avoid many useless assignments.
While there are other variables in these tests, they're not part of the
setup of the test, and so these ones can be removed while keeping the
code easy to read.
The tests in the `spec/lib/graphql_spec.rb` failed sometimes because
creating a record with a tag list of ["health"] when both "health" and
"Health" tags exist might assign either one of them. These tests usually
pass because we create two records and just by chance usually one of the
records gets one tag and the other one gets the other tag. However, the
test was written as if we expected the first record to get the first tag
and the second record to get the second tag, while very often the tests
were passing because the first record got the second tag and the second
record got the first tag. And when both records get the same tag, the
tests fail.
So I've changed these tests to tags are assigned directly and, since we
want to test the `tag_list` method, I've also added some tests to the
Tag model, which reflect the current behaviour: a random tag is assigned
when several tags with the same case-insensitive name exist.
Another option to assign the right tag to the record we're creating
would be to add `ActsAsTaggableOn.strict_case_match = true` to an
initializer. However, that would also create new tags on the database
when we accidentally assign a tag like "hEaLth" (like in the test we add
in this commit). Ideally we would have a strict case match for existing
tags and a non-strict case match for new tags, but I haven't found a way
to do it.
Proposal, Debate and Comment "globalize_accessors" class method were
loaded before application available locales initialization because of
graphql initializer. This will cause unexpected translation errors at
any translatable classes declared at graphql api definition (api.yml).
Doing GraphQL initialization after application initialization should
solve this issue.