Implement delete for Security::Attribute to enable async association cleanup
Problem
Currently, when deleting a Security::Attribute, the database foreign key constraint has on_delete: :cascade (see db/migrate/20250717114003_create_project_to_security_attributes.rb:12), which automatically
deletes all associated project_to_security_attributes records immediately.
This causes two issues:
- Performance: An attribute can have up to 15,000+ associated projects, making synchronous deletion slow
- Audit trail: We cannot properly audit the deletion of project associations since they cascade automatically
The current Security::Attributes::DestroyService enqueues a cleanup worker after deletion (line 45), but by then the associations are already gone due to the cascade.
Proposed Solution
Implement soft delete for Security::Attribute to allow asynchronous batch deletion with proper auditing:
Implementation Steps
-
Add
deleted_atcolumn tosecurity_attributestable- Add migration with
t.datetime_with_timezone:deleted_at - Add an index on
deleted_atfor performance
- Add migration with
-
Implement soft delete behavior in
Security::Attributemodel- Add scope to exclude deleted records:
scope:not_deleted, -> { where(deleted_at: nil) } - Override destroy to set
deleted_atinstead of hard delete - Update existing queries to filter out soft-deleted records
- Add scope to exclude deleted records:
-
Update
Security::Attributes::DestroyService- Change
attribute.destroytoattribute.update(deleted_at: Time.current) - Keep the worker enqueued for async cleanup
- Change
-
Update
Security::Attributes::CleanupProjectToSecurityAttributeWorker- Process
project_to_security_attributesin batches (e.g., 1000 records at a time) - Audit each batch deletion
- After all associations are deleted, perform hard delete:
attribute.destroy!orattribute.really_destroy!
- Process
-
Remove cascade from foreign key (optional but recommended)
- Change
on_delete: :cascadetoon_delete: :restrictto prevent accidental cascades
- Change
Benefits
-
✅ Attribute appears deleted to users immediately (no performance impact) -
✅ Associations cleaned up asynchronously in batches -
✅ Proper audit trail for all project association removals -
✅ Can recover if cleanup fails -
✅ No data integrity issues
Related Files
ee/app/models/security/attribute.rbee/app/services/security/attributes/destroy_service.rbdb/migrate/20250717114003_create_project_to_security_attributes.rb- Worker:
ee/app/workers/security/attributes/cleanup_project_to_security_attribute_worker.rb