Module: ConcernsOnRails::Controllers::Timezoneable

Extended by:
ActiveSupport::Concern
Defined in:
lib/concerns_on_rails/controllers/timezoneable.rb

Overview

Per-request Time.zone selection from the request params, the Time-Zone header, and/or a cookie, wrapped in an around_action so Time.zone is set for the action and restored afterwards. The time analogue of Localizable (which does the same for I18n.locale). Dependency-free.

class ApplicationController < ActionController::Base
include ConcernsOnRails::Controllers::Timezoneable

timezoneable available: ["UTC", "Eastern Time (US & Canada)"], default: "UTC"
# timezoneable param: :tz, header: false, cookie: :time_zone
end

Resolution order: params[param]Time-Zone header → cookie (if enabled) → default → the current Time.zone. Every value — the configured available:/default: AND each request candidate — is resolved through ActiveSupport::TimeZone[...], so a zone accepted at boot can never be rejected at request time.

Options: available: (allow-list applied to param/header/cookie matching; default: bypasses it, mirroring Localizable), default:, param: (default :time_zone), header: (default true), cookie: (default false; true reads the :time_zone cookie, or pass a cookie name).

Defined Under Namespace

Modules: ClassMethods

Instance Method Summary collapse

Instance Method Details

#resolved_time_zoneObject

The ActiveSupport::TimeZone chosen for this request — always one Time can switch to (falls back to the current Time.zone). Memoized per request: resolution costs up to three TimeZone lookups plus an allow-list scan.



81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/concerns_on_rails/controllers/timezoneable.rb', line 81

def resolved_time_zone
  @resolved_time_zone ||= begin
    opts = self.class.timezoneable_options
    allowed = opts[:available]
    candidate = zone_from_param(opts, allowed) ||
                zone_from_header(opts, allowed) ||
                zone_from_cookie(opts, allowed) ||
                opts[:default]

    resolve_zone(candidate) || Time.zone
  end
end

#switch_time_zoneObject

Public so subclasses can override; runs the action under the resolved zone. UNGUARDED on purpose — it touches Time globally, not the response (mirrors Localizable#switch_locale).



67
68
69
70
71
72
73
74
75
# File 'lib/concerns_on_rails/controllers/timezoneable.rb', line 67

def switch_time_zone(&)
  zone = resolved_time_zone
  # Skip the wrapper when it would be a no-op — with nothing configured
  # (or the client asking for the current zone) every action used to run
  # inside a pointless Time.use_zone block.
  return yield if Time.zone && zone && zone.name == Time.zone.name

  Time.use_zone(zone, &)
end