Skip to content

Validate time zones against the Rails time zone list - #155

Merged
dadachi merged 3 commits into
mainfrom
fix/validate-time-zone
Oct 15, 2026
Merged

dadachi merged 3 commits into
mainfrom
fix/validate-time-zone

Conversation

@dadachi

@dadachi dadachi commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Shop#time_zone and Shopkeeper#time_zone accepted any string. In the sibling app myturntagapi an unknown zone reached ActiveSupport::TimeZone[time_zone].something and returned 500. This repo has no such lookup (grep time_zone app/ only finds permits, serializers, madmin and Account#create_default_shop! copying the owner's zone), so here a bogus value was not a crash: it was stored and returned with 200. It is still invalid data the iOS/Android time zone pickers cannot show, and generated apps that add a lookup would 500, so this adds the validation anyway.

  • validates :time_zone, inclusion: {in: ->(_) { ActiveSupport::TimeZone.all.map(&:name) }} on Shop and Shopkeeper (same style as the existing locale validation).
  • Unknown zones get 422 with the standard message: "Time zone is not included in the list" / 「タイムゾーンは一覧から選択してください」 (no model-specific override exists for time_zone).
  • IANA ids are rejected: ActiveSupport::TimeZone["Asia/Tokyo"] does resolve (to a zone named Asia/Tokyo), but it is not in ActiveSupport::TimeZone.all, and the apps send Rails names (Tokyo).
  • New guard test/config/time_zones_test.rb: ActiveSupport::TimeZone.all.map { |z| [z.name, z.to_s] } must equal test/fixtures/files/rails_time_zones.tsv (152 lines, activesupport 8.1.4). The iOS (TimeZoneData.swift / TimeZoneDataTest) and Android (TimeZones.kt / TimeZonesTest) apps embed the same list; when the test fails after a Rails or tzdata upgrade, update the fixture and both apps.

Tests (red, then green)

New tests failed before the validation (5 failures, all "accepted"/200 instead of rejected/422; no 500):

  • ShopTest / ShopkeeperTest: every ActiveSupport::TimeZone.all name accepted; "Bogus", "", "Asia/Tokyo" rejected
  • ShopsControllerTest: PATCH with time_zone: "Bogus" returns 422 and leaves the zone unchanged
  • RegistrationsControllerTest: PATCH /shopkeeper_auth and sign-up with "Bogus" return 422 (sign-up creates no shopkeeper, account or shop)

All pass with the validation. The guard test was broken deliberately (Tokyo label edited to Tokio in the fixture) and failed, then restored.

Existing data: fixtures and seeds use Tokyo, Osaka and the schema default London, all valid; the dev database has 0 invalid shops/shopkeepers. This repo is a template with no production data. A generated app with existing invalid rows would see saves of those records fail until the zone is fixed (and Account#create_default_shop! would raise for an owner with an invalid zone), so such apps should clean up data first.

bin/ci passes locally (rubocop, erb_lint, bundler-audit, brakeman, 622 tests, seeds).

🤖 Generated with Claude Code

https://claude.ai/code/session_01YDK5huvuRECyVrsQEdTN9q

dadachi and others added 3 commits October 15, 2026 18:22
Shop and Shopkeeper accepted any time_zone string. Nothing in this API
looks the zone up, so a bogus value was stored silently (200) rather than
crashing, but the apps would then show or send a zone their pickers
do not know. Both models now require a name from
ActiveSupport::TimeZone.all, so unknown zones (and IANA ids such as
"Asia/Tokyo", which TimeZone[] would resolve but the apps never send)
get 422.

A guard test pins ActiveSupport::TimeZone.all (name and label) to
test/fixtures/files/rails_time_zones.tsv, the list the iOS and Android
apps embed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDK5huvuRECyVrsQEdTN9q
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDK5huvuRECyVrsQEdTN9q
A stored zone that is not a Rails name (from an app generated before this
check) would otherwise block every later save of that record, even one
that does not touch the zone. Matches myturntagapi.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDK5huvuRECyVrsQEdTN9q
@dadachi
dadachi merged commit 9f9577a into main Oct 15, 2026
3 checks passed
@dadachi
dadachi deleted the fix/validate-time-zone branch October 15, 2026 09:29
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