Alphabetize the Product Drive Participant drop-downs (#5593) - #5656
Alphabetize the Product Drive Participant drop-downs (#5593)#5656pcbeingused333 wants to merge 1 commit into
Conversation
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". `DISPLAY_NAME_ORDER` is an ORDER BY expression that lowercases the displayed name 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. It is written as a literal with no interpolation, so it cannot carry a value in. `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>
3eea900 to
d3a1ffb
Compare
|
Pushed a fix for the Brakeman failure — it was mine, and it had been red since I opened this.
I also rebased onto current Verified locally with Brakeman 8.0.5 — The workflows are currently showing |
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.alphabetizedordered bycontact_name, but every drop-down showsbusiness_nameand only falls back tocontact_namewhen 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 nameuses the database collation, which is not the same everywhere. AC.UTF-8cluster (whatbin/setupgave me for dev and test) puts every capitalised name before every lowercase one; thepostgres:12.3image CI runs is initialised withen_US.utf8and doesn't. Same code, different list — and a test that pins the order can pass in CI while the user sees something else.product_drive_participants/create.js.erbrebuilt 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_namealone, so participants who only have a contact name showed up as blank entries.What changed
NaturallySortable.natural_orderbuilds 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 asschema.rb, which carries neither, so both would disappear ondb:schema:load.alphabetizednow sorts onCOALESCE(NULLIF(business_name, ''), contact_name)— the value the user actually reads — through that expression.create.js.erbuses the scope again, and all three places label options with the existingdisplay_namemethod, so the sort key and the label can't drift apart.Verified
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.