Module: Sessions::EngineHelper
- Defined in:
- app/helpers/sessions/engine_helper.rb
Overview
View helpers for the devices page (and for the host-renderable partials).
Constant Summary collapse
- DEVICE_ICONS =
{ "desktop" => "🖥", "smartphone" => "📱", "tablet" => "📱", "native_ios" => "📱", "native_android" => "📱", "bot" => "🤖" }.freeze
- DEVICE_ICON_NAMES =
Semantic icon names (Heroicons vocabulary — map them onto whatever icon helper your app uses) so custom views don’t re-derive the device_type → icon mapping the gem already knows.
{ "desktop" => "computer-desktop", "smartphone" => "device-phone-mobile", "tablet" => "device-tablet", "native_ios" => "device-phone-mobile", "native_android" => "device-phone-mobile", "bot" => "bug-ant" }.freeze
- EVENT_ICON_NAMES =
{ "login" => "check-circle", "failed_login" => "x-circle", "logout" => "arrow-right-on-rectangle", "revoked" => "no-symbol", "expired" => "clock" }.freeze
Class Method Summary collapse
-
.engine_mount_name ⇒ Object
The name of the route that mounts Sessions::Engine in the host app (“sessions” for a plain mount, the ‘as:` value otherwise).
- .reset_engine_mount_name! ⇒ Object
Instance Method Summary collapse
- #sessions_device_icon(session) ⇒ Object
- #sessions_device_icon_name(session) ⇒ Object
-
#sessions_engine_routes ⇒ Object
The engine’s route proxy when it’s mounted, nil otherwise — partials rendered inside a host that didn’t mount the engine simply omit the revoke buttons.
- #sessions_event_icon_name(event) ⇒ Object
-
#sessions_format_date(date) ⇒ Object
“Signed in May 2, 2026” — localized when the host bundles date formats (rails-i18n or its own locale files), with a safe fallback so a bare host never 500s over a missing ‘date.formats.long`.
- #sessions_format_time(time) ⇒ Object
-
#sessions_last_active_in_words(session) ⇒ Object
“Active now” within the touch window, else “Active 3 minutes ago”.
Class Method Details
.engine_mount_name ⇒ Object
The name of the route that mounts Sessions::Engine in the host app (“sessions” for a plain mount, the ‘as:` value otherwise). Memoized per-process; in development a changed mount name reloads routes and to_prepare re-touches this helper file, clearing the memo.
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'app/helpers/sessions/engine_helper.rb', line 74 def self.engine_mount_name return @engine_mount_name if defined?(@engine_mount_name) @engine_mount_name = begin route = Rails.application.routes.routes.find do |candidate| # The mount sits behind a Constraints wrapper; unwrap a bounded # number of times, checking BEFORE each unwrap — Rails::Engine # itself responds to #app (its middleware stack), so an unguarded # `while app.respond_to?(:app)` would walk straight past it. app = candidate.app matched = false 3.times do matched = (app == Sessions::Engine) break if matched || !app.respond_to?(:app) app = app.app end matched end route&.name rescue StandardError nil end end |
.reset_engine_mount_name! ⇒ Object
99 100 101 |
# File 'app/helpers/sessions/engine_helper.rb', line 99 def self.reset_engine_mount_name! remove_instance_variable(:@engine_mount_name) if defined?(@engine_mount_name) end |
Instance Method Details
#sessions_device_icon(session) ⇒ Object
36 37 38 |
# File 'app/helpers/sessions/engine_helper.rb', line 36 def sessions_device_icon(session) DEVICE_ICONS.fetch(session.device_type.to_s, "🌐") end |
#sessions_device_icon_name(session) ⇒ Object
40 41 42 |
# File 'app/helpers/sessions/engine_helper.rb', line 40 def sessions_device_icon_name(session) DEVICE_ICON_NAMES.fetch(session.device_type.to_s, "globe-alt") end |
#sessions_engine_routes ⇒ Object
The engine’s route proxy when it’s mounted, nil otherwise — partials rendered inside a host that didn’t mount the engine simply omit the revoke buttons. The proxy method is named after the mount (‘sessions` by default, or whatever `as:` was given), so it’s DISCOVERED from the host’s named routes rather than assumed.
65 66 67 68 |
# File 'app/helpers/sessions/engine_helper.rb', line 65 def sessions_engine_routes name = Sessions::EngineHelper.engine_mount_name name && respond_to?(name) ? public_send(name) : nil end |
#sessions_event_icon_name(event) ⇒ Object
44 45 46 |
# File 'app/helpers/sessions/engine_helper.rb', line 44 def sessions_event_icon_name(event) EVENT_ICON_NAMES.fetch(event.event.to_s, "information-circle") end |
#sessions_format_date(date) ⇒ Object
“Signed in May 2, 2026” — localized when the host bundles date formats (rails-i18n or its own locale files), with a safe fallback so a bare host never 500s over a missing ‘date.formats.long`. nil-safe: without the guard, I18n.l(nil) raises I18n::ArgumentError and the rescue would then call nil.strftime — a trap for custom views passing a nullable column.
109 110 111 112 113 114 115 |
# File 'app/helpers/sessions/engine_helper.rb', line 109 def sessions_format_date(date) return nil unless date I18n.l(date, format: :long) rescue I18n::MissingTranslationData, I18n::ArgumentError date.strftime("%Y-%m-%d") end |
#sessions_format_time(time) ⇒ Object
117 118 119 120 121 122 123 |
# File 'app/helpers/sessions/engine_helper.rb', line 117 def sessions_format_time(time) return nil unless time I18n.l(time, format: :short) rescue I18n::MissingTranslationData, I18n::ArgumentError time.strftime("%Y-%m-%d %H:%M") end |
#sessions_last_active_in_words(session) ⇒ Object
“Active now” within the touch window, else “Active 3 minutes ago”.
49 50 51 52 53 54 55 56 57 58 |
# File 'app/helpers/sessions/engine_helper.rb', line 49 def sessions_last_active_in_words(session) # active_now? owns the window (config.touch_every) — the badge can't # honestly claim more freshness than the throttle records. return t("sessions.devices.active_now") if session.respond_to?(:active_now?) && session.active_now? time = session.last_active_at return nil unless time t("sessions.devices.active_ago", time: time_ago_in_words(time)) end |