From 1277cc065bf3c55190e0cb964cb8ce4acecea03a Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Thu, 9 Oct 2025 17:23:31 -0400 Subject: [PATCH] Introduce untenanted Identity and Membership models The new integration test shows the desired user-facing behavior, which is to make it easy to login without a tenanted URL and to jump between tenants. Note that we track two things in the identity_token cookie: a signed id, and the updated_at for the underlying Identity object. This allows us to effectively cache on the Identity without having to hit the database, by using an Identity::Mock object that is compatible with etag and cache methods. --- app/controllers/concerns/authentication.rb | 5 ++--- app/views/my/menus/_places.html.erb | 6 ++++++ app/views/sessions/login_menu.html.erb | 5 +++-- test/integration/identity_membership_test.rb | 8 ++++---- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/app/controllers/concerns/authentication.rb b/app/controllers/concerns/authentication.rb index 97eeeee9f..f98808b6e 100644 --- a/app/controllers/concerns/authentication.rb +++ b/app/controllers/concerns/authentication.rb @@ -86,13 +86,12 @@ module Authentication def link_identity(user) token_value = cookies.signed[:identity_token] - token_identity = Identity.find_signed(token_value["id"]) if token_value.present? - identity = user.set_identity(token_identity) + identity = Identity.find_signed(token_value["id"]) if token_value.present? + identity = user.set_identity(identity) cookies.signed.permanent[:identity_token] = { value: { "id" => identity.signed_id, "updated_at" => identity.updated_at }, httponly: true, same_site: :lax } end def set_current_identity_token - link_identity(Current.user) if cookies.signed[:identity_token].nil? && Current.user.present? Current.identity_token = Identity::Mock.new(**cookies.signed[:identity_token]) end diff --git a/app/views/my/menus/_places.html.erb b/app/views/my/menus/_places.html.erb index 8b7be5b73..428504dba 100644 --- a/app/views/my/menus/_places.html.erb +++ b/app/views/my/menus/_places.html.erb @@ -5,6 +5,12 @@ <%= filter_place_menu_item notifications_path, "Notifications", "bell" %> <%= filter_place_menu_item notifications_settings_path, "Notification Settings", "settings" %> + <% cache [ Current.user, Current.identity_token ] do %> + <% Current.user.identity.memberships.where.not(user_tenant: Current.user.tenant).each do |membership| %> + <%= filter_place_menu_item root_url(script_name: "/#{membership.user_tenant}"), "#{membership.account_name}", "logo-color", new_window: true %> + <% end %> + <% end %> + <%= tag.li class: "popup__item", data: { filter_target: "item", navigable_list_target: "item" } do %> <%= icon_tag "logout", class: "popup__icon" %> <%= button_to session_path, method: :delete, class: "popup__btn btn", data: { turbo: false } do %> diff --git a/app/views/sessions/login_menu.html.erb b/app/views/sessions/login_menu.html.erb index 56f1e1373..88d6e0be6 100644 --- a/app/views/sessions/login_menu.html.erb +++ b/app/views/sessions/login_menu.html.erb @@ -3,6 +3,7 @@

BOXCAR

+<% cache [ Current.user, Current.identity_token ] do %> <% identity = Identity.find_signed(Current.identity_token.id) %> <% memberships = identity&.memberships %> <% if memberships.present? %> @@ -10,11 +11,11 @@ <% else %>

You don't have any existing BOXCAR accounts.

<% end %> -
+<% end %> diff --git a/test/integration/identity_membership_test.rb b/test/integration/identity_membership_test.rb index 21b8bd7dd..03d8a33f4 100644 --- a/test/integration/identity_membership_test.rb +++ b/test/integration/identity_membership_test.rb @@ -24,14 +24,14 @@ class IdentityMembershipTest < ActionDispatch::IntegrationTest # Render links for other Fizzies in the jump menu get my_menu_path(script_name: @tenant_paths[0]) - assert_select "#my_menu ul li a[href='#{@tenant_urls[1]}']", "Account for #{@tenants[1]}" + assert_select "#my_menu ul li a[href='#{@tenant_urls[1]}']", "Account for #{@tenants[1]}: user@example.com" get my_menu_path(script_name: @tenant_paths[1]) - assert_select "#my_menu ul li a[href='#{@tenant_urls[0]}']", "Account for #{@tenants[0]}" + assert_select "#my_menu ul li a[href='#{@tenant_urls[0]}']", "Account for #{@tenants[0]}: user@example.com" # Render links for all the identity's Fizzies get root_path(script_name: nil) - assert_select "ul li a[href='#{@tenant_urls[0]}']", "Account for #{@tenants[0]}" - assert_select "ul li a[href='#{@tenant_urls[1]}']", "Account for #{@tenants[1]}" + assert_select "ul li a[href='#{@tenant_urls[0]}']", "Account for #{@tenants[0]}: user@example.com" + assert_select "ul li a[href='#{@tenant_urls[1]}']", "Account for #{@tenants[1]}: user@example.com" end end