Skip to content

Alphabetize the Product Drive Participant drop-downs (#5593) - #5656

Open
pcbeingused333 wants to merge 1 commit into
rubyforgood:mainfrom
pcbeingused333:5593-alphabetize-participant-dropdowns
Open

Alphabetize the Product Drive Participant drop-downs (#5593)#5656
pcbeingused333 wants to merge 1 commit into
rubyforgood:mainfrom
pcbeingused333:5593-alphabetize-participant-dropdowns

Conversation

@pcbeingused333

Copy link
Copy Markdown

Part of #5593 — the two drop-downs named in the issue. The survey of every other drop-down in the app is posted as a comment on the issue, per @dorner's suggestion that its results inform a separate ticket.

What was wrong

ProductDriveParticipant.alphabetized ordered by contact_name, but every drop-down shows business_name and only falls back to contact_name when it is blank — so the lists were sorted on a column the user cannot see.

Sorting on the displayed name isn't enough on its own:

  • ORDER BY name uses the database collation, which is not the same everywhere. A C.UTF-8 cluster (what bin/setup gave me for dev and test) puts every capitalised name before every lowercase one; the postgres:12.3 image CI runs is initialised with en_US.utf8 and doesn't. Same code, different list — and a test that pins the order can pass in CI while the user sees something else.
  • Plain text ordering isn't natural: "Store 10" sorts before "Store 9", which the issue's completion criteria rules out.

product_drive_participants/create.js.erb rebuilt the drop-down without the ordering scope at all, so the new-donation list lost its order as soon as a participant was added from the modal.

The donation filter labelled its options with business_name alone, so participants who only have a contact name showed up as blank entries.

What changed

  • NaturallySortable.natural_order builds an ORDER BY expression that lowercases the value and zero-pads runs of digits, so ordering is case-insensitive and natural regardless of the cluster's collation. It's an expression rather than a Postgres function or an ICU collation on purpose: the schema is maintained as schema.rb, which carries neither, so both would disappear on db:schema:load.
  • alphabetized now sorts on COALESCE(NULLIF(business_name, ''), contact_name) — the value the user actually reads — through that expression.
  • create.js.erb uses the scope again, and all three places label options with the existing display_name method, so the sort key and the label can't drift apart.

Verified

  • New model specs cover both the fallback to contact name and "Store 2 / Store 9 / Store 10".
  • bundle exec rspec spec/models/product_drive_participant_spec.rb spec/requests/donations_requests_spec.rb spec/requests/product_drive_participants_requests_spec.rb spec/system/donation_system_spec.rb spec/system/product_drive_participant_system_spec.rb, rubocop and erb_lint all pass locally.

The `alphabetized` scope ordered by `contact_name`, but every dropdown shows
`business_name` and only falls back to `contact_name` when it is blank, so the
lists were sorted on a column the user cannot see.

Sorting on the displayed name is not enough on its own. `ORDER BY name` uses the
database collation, which differs between environments: a `C.UTF-8` cluster puts
every capitalised name before every lowercase one, while the `postgres:12.3`
image CI runs is initialised with `en_US.utf8` and does not. Plain text ordering
also puts "Store 10" before "Store 9".

`NaturallySortable.natural_order` builds an ORDER BY expression that lowercases
the value and zero-pads runs of digits, so the ordering is case-insensitive and
natural whatever the cluster's collation is. It is an expression rather than a
Postgres function or an ICU collation because the schema is maintained as
`schema.rb`, which carries neither.

`create.js.erb` rebuilt the dropdown without the scope at all, so the list lost
its order as soon as a participant was added from the modal. It now reuses
`display_name`, which is also what the donation form and the donation filter
label the options with, so the sort key and the label can no longer drift apart.
The donation filter previously labelled options with `business_name` alone,
leaving participants who only have a contact name as blank entries.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant