Skip to content

Remove hack in the Invitations backend - #4370

Open
jlledom wants to merge 4 commits into
masterfrom
remove-invitations-hack
Open

Remove hack in the Invitations backend#4370
jlledom wants to merge 4 commits into
masterfrom
remove-invitations-hack

Conversation

@jlledom

@jlledom jlledom commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

What this PR does / why we need it:

I found this horrible hack while working on #4369 and I couldn't help but fix it in this PR.

The hack comes from Rails 3 times, it seemed to try to fix a Rails bug when using association in the inverse way: Instead of creating the invite from the user, we want to create the user from the invite side. So we are creating the strong side from the weak side of the relation.

I didn't investigate further, so maybe this wasn't the reason of the hack, but anyway, using a has_one association works perfect, all tests pass, etc. So I think whatever the problem was in Rails 3, it's solved now.

You can check the original PR for further info: https://github.com/3scale/system/pull/3483/changes. About this PR, it's a pretty simple change, it should work without issues. The PR also includes the fix for Qlty comments and improves existing tests.

Which issue(s) this PR fixes

No Jira issue

Verification steps

  1. Send an invitation, no matter for developer or admin portal user
  2. You should receive an email with the activation code, open it on a private window
  3. Create the new user, no matter if it's via signup or via SSO
  4. The user should work fine: be activaded, be able to login, etc.
  5. The Invitation should appear as accepted
  6. Remove the user
  7. The invitation should disappear from the list, in the invitations screen

…ation

The User model used an attr_accessor for :invitation instead of a proper
has_one association. This was a Rails 3 workaround needed because the
inverse association wasn't reliably set in memory when building a user
through Invitation#make_user.

Modern Rails handles has_one/belongs_to inverses correctly, so the
attr_accessor is no longer needed. Removing it also means the
invitation no longer needs to pass itself as a user attribute; the
association is wired automatically when self.user is assigned on the
invitation side.

Assisted-by: Claude Code
The invitation signup tests verified user creation and
activation but never checked that the invitation itself
was marked as accepted. This is the key side-effect of the
after_commit :accept_invitation callback, and the behavior
most likely to regress after replacing the attr_accessor
hack with a real has_one association.

Assisted-by: Claude Code
@jlledom jlledom self-assigned this Aug 10, 2026
@qltysh

qltysh Bot commented Aug 10, 2026

Copy link
Copy Markdown

2 new issues

Tool Category Rule Count
qlty Duplication Found 18 lines of similar code in 2 locations (mass = 93) 2

Comment thread app/models/user/invitations.rb Outdated
Comment thread app/models/user/invitations.rb Outdated
assert result.active?
assert authentication_strategy.error_message.blank?
assert invitation.reload.accepted?
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found 18 lines of similar code in 2 locations (mass = 93) [qlty:similar-code]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm gonna ignore these, I don't see the problem on the duplication, these are tests.

assert result.active?
assert authentication_strategy.error_message.blank?
assert invitation.reload.accepted?
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found 18 lines of similar code in 2 locations (mass = 93) [qlty:similar-code]

Dynamic finder methods (find_by_email, find_by_user_id) are
deprecated in favour of find_by(attr:) syntax. Also caches
account.invitations into a local variable to avoid calling
the same method twice, addressing the reek DuplicateMethodCall
warning flagged in code review.

Assisted-by: Claude Code
rubocop requires a :dependent option on has_one/has_many
associations. In this case the before_destroy callback
already handles invitation destruction (with an abort guard
if destruction fails), so adding a Rails-managed dependent
option would conflict. Suppressing the cop with an inline
comment explains the intentional design.

Assisted-by: Claude Code
@jlledom jlledom changed the title Remove invitations hack Remove hack in the Invitations backend Aug 10, 2026
@jlledom
jlledom marked this pull request as ready for review August 17, 2026 07:19

@madnialihussain madnialihussain left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants