WAIT: Support international addresses with country-driven state field#1855
WAIT: Support international addresses with country-driven state field#1855maebeale wants to merge 1 commit into
Conversation
AWBW now serves people and orgs outside the US, but every address forced a US-state dropdown and required a US state, so international addresses couldn't be entered or registered. Drive the state field off the country instead: - Address forms swap the validated US-state dropdown for a required free-text region input whenever the country isn't the United States (new address-region Stimulus controller; country is a real dropdown via the countries gem). - Address validates state is a recognized US abbreviation only for US addresses (case-insensitive); international addresses just require a value. - Public registration persists the submitted country and keeps the state field free-text so non-US registrants can enter their region; the same model rules reject an invalid US state. - Address#name drops a blank/again-optional region without a stray separator. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| # US addresses must use a recognized state abbreviation; international addresses | ||
| # store a free-form region, so they only need a value (presence above). The check | ||
| # is case-insensitive to tolerate legacy lowercase abbreviations (e.g. "tx"). | ||
| validate :state_is_a_us_state, if: :united_states? |
There was a problem hiding this comment.
🤖 From Claude: The US-state check only runs when united_states? (blank/US country). International addresses just need a value, so a region like "Ontario" passes. The check itself is case-insensitive (see state_is_a_us_state) to tolerate legacy lowercase abbreviations the dashboard already normalizes.
| def create_mailing_address(person) | ||
| new_city = field_value("mailing_city")&.strip | ||
| new_state = field_value("mailing_state")&.strip | ||
| new_country = field_value("mailing_country")&.strip.presence |
There was a problem hiding this comment.
🤖 From Claude: The form already collected mailing_country but the service never saved it. That gap is load-bearing now: without a country, an international address defaults to domestic and the new US-state validation would reject the region. Persisting it (also for agency_country) is what lets non-US registrations through.
| class: "block w-full rounded-md border-gray-300 shadow-sm focus:ring-blue-500 focus:border-blue-500" %> | ||
| </div> | ||
| <div data-address-region-wrapper class="<%= "hidden" if domestic %>"> | ||
| <%= f.label :state, "State / region", for: f.field_id(:state, :region), |
There was a problem hiding this comment.
🤖 From Claude: Both state inputs bind to the same state attribute, so the inactive one is disabled (not just hidden) — disabled fields do not submit, so exactly one value posts. Initial visibility is server-rendered from the stored country so there is no flash before the Stimulus controller connects.
What is the goal of this PR and why is this important?
How did you approach the change?
countryis now a real dropdown (via thecountriesgem, defaulting to United States). A newaddress-regionStimulus controller shows a validated US-state dropdown when the country is the US, and swaps to a required free-text region input otherwise. Only the active input is enabled, so exactly one value submits.Addressrequires a state, but only enforces a recognized US abbreviation (case-insensitive, to tolerate legacy lowercase) when the country is the US; international addresses just need a value.Address#namedrops a blank region without leaving a stray separator.UsStatemodule used by both the dropdown and the validation, so options and accepted values can't drift.mailing_country/agency_country, and the public state field is free-text (US states offered as datalist suggestions) so non-US registrants can enter their region. The same model rules reject an invalid US state.UI Testing Checklist
Anything else to add?
EventDashboard) is unchanged: it still buckets recognized US abbreviations into the States map, leaving international regions for the Countries map.address-regioncontroller is scoped per address block, so cocoon-added addresses work too.🤖 Generated with Claude Code