Skip to content

Conversation

@compwron
Copy link
Collaborator

@compwron compwron commented Jan 5, 2026

Screenshot 2026-01-05 at 5 04 48 PM
Controller: case_contacts/form#update
Affected User: xxx@gmail.com, 180
App URL: https://casavolunteertracking.org/case_contacts/82063/form/details
Time: Mon Jan 05 2026 13:58 (Central Standard Time)
Environment: production
Message: Validation failed: Case contact has already been taken
Error URL: https://api.bugsnag.com/projects/5f370b68136a4b0010d15364/events/695c17da01612787745e0000
Stack:
  File: app/controllers/case_contacts/form_controller.rb:27
    respond_to do |format|
      format.html do
        params[:case_contact][:status] = CaseContact.statuses[step] if !@case_contact.active?
        if @case_contact.update(case_contact_params)
          finish_editing
        else
          prepare_form

  File: app/controllers/case_contacts/form_controller.rb:24
    remove_unwanted_contact_types
    remove_nil_draft_ids

    respond_to do |format|
      format.html do
        params[:case_contact][:status] = CaseContact.statuses[step] if !@case_contact.active?
        if @case_contact.update(case_contact_params)


Controller: case_contacts/form#update
Affected User: xxx@gmail.com, 180
App URL: https://casavolunteertracking.org/case_contacts/82063/form/details
Time: Mon Jan 05 2026 13:58 (Central Standard Time)

@github-actions github-actions bot added ruby Pull requests that update Ruby code Tests! 🎉💖👏 labels Jan 5, 2026
@compwron compwron requested a review from Copilot January 6, 2026 01:05
@compwron compwron changed the title WIP fix Big fix: Validation failed: Case contact has already been taken Jan 6, 2026
@compwron compwron changed the title Big fix: Validation failed: Case contact has already been taken Bug fix: Validation failed: Case contact has already been taken Jan 6, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a production bug where updating case contact contact types was causing a "Validation failed: Case contact has already been taken" uniqueness validation error. The root cause was the remove_unwanted_contact_types method calling destroy_all on the join table associations before the update, creating a timing issue where Rails would attempt to create duplicate join records that violated the uniqueness constraint in CaseContactContactType.

Key changes:

  • Removed the remove_unwanted_contact_types method that was manually destroying associations
  • Removed the call to this method in the update action, allowing Rails to handle association updates atomically
  • Added comprehensive test coverage for various contact type update scenarios

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
app/controllers/case_contacts/form_controller.rb Removed the manual destroy_all approach for contact type associations, allowing Rails to manage the has_many :through relationship updates properly
spec/requests/case_contacts/form_spec.rb Added six new test cases covering overlapping updates, consecutive updates, reducing/expanding contact types, and complete replacements to prevent regression of the uniqueness validation error

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

end

it "handles overlapping contact types (mix of existing and new)" do
# Prevent regression: Rails should update associations without destroy_all race condition
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment "Prevent regression" is misleading here. This test verifies the fixed behavior after removing the destroy_all call, rather than preventing future regressions. Consider rephrasing to something like "Verifies that overlapping contact types can be updated without uniqueness errors" to more accurately describe what the test does.

Suggested change
# Prevent regression: Rails should update associations without destroy_all race condition
# Verifies that overlapping contact types can be updated without destroy_all-related race conditions

Copilot uses AI. Check for mistakes.

case_contact.reload
expect(case_contact.contact_type_ids).to contain_exactly(contact_types.first.id)
expect(case_contact.contact_type_ids).not_to include(contact_types.second.id)
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This expectation is redundant. The previous line already asserts that contact_type_ids contains exactly the first contact type ID, which implicitly means it does not include the second contact type ID. Consider removing this line to reduce test verbosity.

Suggested change
expect(case_contact.contact_type_ids).not_to include(contact_types.second.id)

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ruby Pull requests that update Ruby code Tests! 🎉💖👏

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants