fix: anchor contact phone number validation (#15415)

Contact phone numbers with stray text in front of them, like
`abc+12312312321`, were saving successfully instead of being rejected as
invalid. Agents could end up with unusable numbers on a contact, and the
same values were persisted rather than discarded when captured through
the live chat widget.

## How to reproduce

1. Open a contact and edit its details.
2. Set the phone number to `abc+12312312321` via the API (`PATCH
/api/v1/accounts/:id/contacts/:id`).
3. Before this change the update succeeds. Now it fails validation.

## What changed

The E.164 format check was missing a leading `\A` anchor, so Rails
matched it anywhere in the string and accepted any prefix ahead of a
valid number. Both the validation and the `phone_number_format` fallback
used by `discard_invalid_attrs` are now anchored, so the widget path
discards these values instead of storing them.

Contacts already holding a prefixed number will now fail validation on
their next save. Worth a count on production first:

```sql
SELECT count(*) FROM contacts WHERE phone_number !~ '^\+[1-9][0-9]{1,14}$' AND phone_number <> '';
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
Shivam Mishra
2026-08-12 15:28:49 +05:30
committed by GitHub
parent 79405f76c4
commit a24f5a3e7a
3 changed files with 14 additions and 2 deletions

View File

@@ -144,6 +144,13 @@ describe ContactIdentifyAction do
expect(contact.reload.name).to eq 'new name'
expect(contact.phone_number).to be_nil
end
it 'discards a phone number that has text prefixed to a valid number' do
params = { phone_number: 'abc+12312312321', name: 'new name' }
described_class.new(contact: contact, params: params, discard_invalid_attrs: true).perform
expect(contact.reload.name).to eq 'new name'
expect(contact.phone_number).to be_nil
end
end
context 'when params have not changed' do

View File

@@ -65,6 +65,11 @@ RSpec.describe Contact do
expect { contact.update!(phone_number: '123456789') }.to raise_error(ActiveRecord::RecordInvalid)
end
it 'will throw error when text is prefixed to a valid phone number' do
contact = create(:contact)
expect { contact.update!(phone_number: 'abc+12312312321') }.to raise_error(ActiveRecord::RecordInvalid)
end
it 'updates phone number when adding valid phone number' do
contact = create(:contact)
expect(contact.update!(phone_number: '+12312312321')).to be true