* fix(conversations): enforce NOT NULL + FK on contact_id
Conversations had contact_id nullable with no FK to contacts. Combined
with dependent: :destroy_async on Contact#conversations, deleting a
contact could leave conversations pointing to a missing contact,
breaking the conversations#index API with
"undefined method 'additional_attributes' for nil" from the contact
partial.
Changes:
- Migration cleans up existing orphans, sets contact_id NOT NULL and
adds a FK with ON DELETE CASCADE so the invariant is enforced at the
DB level (complements the existing Rails presence validation).
- ContactMergeAction uses update_all for conversations/messages/notes/
contact_inboxes so a failing callback cannot silently leave records
pointing to the mergee contact before it is destroyed.
- Drop the now-redundant orphan filter in Conversations::ResolutionJob
and its spec; the invariant is enforced at the schema level.
* fix: address review feedback
- Drop the ON DELETE CASCADE FK on conversations.contact_id. Several
conversation-owned tables (messages, mentions, conversation_participants,
reporting_events, csat_survey_responses, calls, applied_slas, sla_events,
and polymorphic notifications) still have plain conversation_id references
without FK cascades. The DB-level cascade would skip Conversation's
dependent: cleanup and replace the NULL-contact bug with orphan children,
and would also conflict with the existing non-cascade FKs on
scheduled_messages/recurring_scheduled_messages. Keep the invariant at the
Rails layer (NOT NULL + presence validation + dependent: :destroy_async).
- Clean up orphan conversations in the migration via Rails destroy so
dependent associations are propagated correctly, instead of a raw
DELETE FROM conversations that would orphan all child rows.
- Revert ContactMergeAction.merge_* methods back to per-record update! so
Conversation#after_update_commit still fires (notify_status_change /
CONVERSATION_CONTACT_CHANGED) for contact_id changes. The bang form
still removes the silent-failure risk of the original .update call.
## Linear Ticket
https://linear.app/chatwoot/issue/CW-4569/nomethoderror-undefined-method-blocked-for-nil-nomethoderror
## Description
Fixes NoMethodError in ConversationMuteHelpers that occurs during
contact deletion race condition.
When a contact is deleted, there's a brief window (~50-150ms) where
contact_id becomes nil but conversations still exist. If ResolutionJob
runs during this window, the muted? method crashes trying to call
blocked? on nil.Fixes # (issue)
## Type of change
- [ ] Bug fix (non-breaking change which fixes an issue)
## How Has This Been Tested?
- Created orphaned conversations (contact_id = nil)
- Called muted?, mute!, unmute! - all return gracefully
- Verified async deletion still works correctly
## Checklist:
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
Co-authored-by: Sojan Jose <sojan@pepalo.com>
### Summary
- Converts conversation auto-resolution duration from days to minutes
for more
granular control
- Updates validation to allow values from 10 minutes (minimum) to 999
days (maximum)
- Implements smart messaging to show appropriate time units in activity
messages
### Changes
- Created migration to convert existing durations from days to minutes
(x1440)
- Updated conversation resolver to use minutes instead of days
- Added dynamic translation key selection based on duration value
- Updated related specs and documentation
- Added support for displaying durations in days, hours, or minutes
based on value
### Test plan
- Verify account validation accepts new minute-based ranges
- Confirm existing account settings are correctly migrated
- Test auto-resolution works properly with minute values
- Ensure proper time unit display in activity messages
---------
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
We will be adding a limit to the resolution job so that it is performed at a spaced interval. This will ensure there won't be a sudden spike in resource usage
fixes: chatwoot/product#707