Add model-level validation for events sharding key

What does this MR do and why?

Adds a model-level validation to Event requiring exactly one of group_id, project_id, or personal_namespace_id to be present per row. This is step 3 of #598786, tightening the sharding key for the events table ahead of the database-level NOT NULL/NOT VALID check constraint (handled in a separate MR).

Changes:

  1. Moves the existing ensure_sharding_key callback from before_save to before_validation, so personal_namespace_id is populated from the author's namespace (when all three keys are nil) before validation runs. This follows the same pattern used by AwardEmoji, SnippetRepository, and SentNotification.
  2. Adds validates_with ExactlyOnePresentValidator for [:group_id, :project_id, :personal_namespace_id], following the established codebase pattern.
  3. Adds specs covering: valid with only project_id / only group_id / only personal_namespace_id, invalid when more than one key is set, and ensure_sharding_key populating personal_namespace_id from the author.
  4. Fixes two EE specs that created events with both project_id (factory default) and group_id set, which now fail the validation.

This revives the approach from the closed draft !241700 (closed) (which additionally sets project: nil in the two EE specs).

Impact on existing records

Per the code quality guidelines on new model validations: the ~14,788 existing violating rows (WikiPage::Meta events with both group_id and personal_namespace_id set) are being cleaned up by the batched background migration from !241192 (merged). That BBM is merged and queued, but not yet finalized — the docs YAML has no finalized_by field, and no post-migration calls ensure_batched_background_migration_is_finished for it. Because violating rows can therefore still exist, this validation is scoped on: :create: existing rows stay saveable, and only newly created events must have exactly one sharding key set.

No current code path produces rows with multiple sharding keys set (see !240292 (merged)), so this scoping doesn't mask a live bug. The on: :create scope should be widened once the BBM is finalized, tracked in #598786.

References

Screenshots or screen recordings

Not applicable: no UI changes.

How to set up and validate locally

  1. In a Rails console, build an event with two sharding keys and confirm it is invalid:
    event = Event.new(action: :created, author: User.first, group: Group.first, project: Project.first)
    event.valid? # => false
    event.errors[:base] # => ["must have exactly one of group_id, project_id, or personal_namespace_id"]
  2. Confirm ensure_sharding_key backfills personal_namespace_id before validation:
    event = Event.new(action: :joined, author: User.first)
    event.valid? # => true
    event.personal_namespace_id # => User.first.namespace_id
  3. Run bundle exec rspec spec/models/event_spec.rb.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Chen Zhang

Merge request reports

Loading
Loading