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:
- Moves the existing
ensure_sharding_keycallback frombefore_savetobefore_validation, sopersonal_namespace_idis populated from the author's namespace (when all three keys are nil) before validation runs. This follows the same pattern used byAwardEmoji,SnippetRepository, andSentNotification. - Adds
validates_with ExactlyOnePresentValidatorfor[:group_id, :project_id, :personal_namespace_id], following the established codebase pattern. - Adds specs covering: valid with only
project_id/ onlygroup_id/ onlypersonal_namespace_id, invalid when more than one key is set, andensure_sharding_keypopulatingpersonal_namespace_idfrom the author. - Fixes two EE specs that created events with both
project_id(factory default) andgroup_idset, 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
- Work item: #598786 (step 3)
- Previous attempt (closed unmerged): !241700 (closed)
- Cleanup BBM (merged): !241192 (merged)
- Removal of the code path that produced violating rows: !240292 (merged)
Screenshots or screen recordings
Not applicable: no UI changes.
How to set up and validate locally
- 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"] - Confirm
ensure_sharding_keybackfillspersonal_namespace_idbefore validation:event = Event.new(action: :joined, author: User.first) event.valid? # => true event.personal_namespace_id # => User.first.namespace_id - 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.