diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb
index 73f718873..31b0bc3f7 100644
--- a/app/controllers/confirmations_controller.rb
+++ b/app/controllers/confirmations_controller.rb
@@ -39,11 +39,12 @@ def create
protected
def after_confirmation_success(resource)
- if resource.welcome_instructions_token.present?
+ if resource.previous_changes.key?("email")
+ redirect_to new_user_session_path, notice: "Your email has been confirmed. Please sign in."
+ elsif resource.welcome_instructions_token.present?
redirect_to user_welcome_path(resource.welcome_instructions_token)
else
- redirect_to new_user_session_path,
- notice: "Your email has been confirmed. Please sign in."
+ redirect_to new_user_session_path, notice: "Your email has been confirmed. Please sign in."
end
end
end
diff --git a/app/views/welcome/show.html.erb b/app/views/welcome/show.html.erb
index b9e52ff7e..0dfd16c4a 100644
--- a/app/views/welcome/show.html.erb
+++ b/app/views/welcome/show.html.erb
@@ -34,7 +34,7 @@
spellcheck: "false",
data: { password_toggle_target: "input" } %>
@@ -56,7 +56,7 @@
spellcheck: "false",
data: { password_toggle_target: "input" } %>
diff --git a/spec/requests/user_invitation_flow_system_spec.rb b/spec/requests/user_invitation_flow_system_spec.rb
index 001634b73..f8d465087 100644
--- a/spec/requests/user_invitation_flow_system_spec.rb
+++ b/spec/requests/user_invitation_flow_system_spec.rb
@@ -143,19 +143,71 @@
expect(response).to redirect_to(user_welcome_path(user_with_token.welcome_instructions_token))
end
- it "redirects to sign in if user has no welcome token" do
- # User without welcome token
- user_without_token = create(:user, confirmed_at: nil)
- user_without_token.update_columns(welcome_instructions_token: nil)
- user_without_token.send_confirmation_instructions
+ it "redirects to welcome page with existing token even if token is old" do
+ # User with old welcome token (tokens no longer expire)
+ user_with_old_token = create(:user, confirmed_at: nil)
+ user_with_old_token.set_welcome_instructions_token!
+ user_with_old_token.update_column(:welcome_instructions_created_at, 31.days.ago)
+ old_token = user_with_old_token.welcome_instructions_token
+ user_with_old_token.send_confirmation_instructions
# Visit confirmation link
- get user_confirmation_path(confirmation_token: user_without_token.confirmation_token)
+ get user_confirmation_path(confirmation_token: user_with_old_token.confirmation_token)
+
+ # Should keep existing token and redirect to welcome page
+ user_with_old_token.reload
+ expect(user_with_old_token.welcome_instructions_token).to eq(old_token)
+ expect(response).to redirect_to(user_welcome_path(user_with_old_token.welcome_instructions_token))
+ end
+
+ it "redirects legacy ported users without welcome token to sign in" do
+ # Legacy user ported from old system — sign_in_count is 0, no welcome token
+ legacy_user = create(:user, confirmed_at: nil)
+ legacy_user.update_columns(welcome_instructions_token: nil, sign_in_count: 0)
+ legacy_user.send_confirmation_instructions
+
+ get user_confirmation_path(confirmation_token: legacy_user.confirmation_token)
- # Should redirect to sign in page
expect(response).to redirect_to(new_user_session_path)
follow_redirect!
expect(response.body).to include("confirmed")
end
+
+ it "redirects to sign in on reconfirmation even with welcome token present" do
+ # Edge case: user has welcome token but is doing an email change
+ user = create(:user, confirmed_at: 1.year.ago)
+ user.set_welcome_instructions_token!
+ user.update_columns(
+ unconfirmed_email: "changed@example.com",
+ confirmation_token: Devise.friendly_token,
+ confirmation_sent_at: Time.current
+ )
+
+ get user_confirmation_path(confirmation_token: user.confirmation_token)
+
+ # Reconfirmation takes priority over welcome token
+ expect(response).to redirect_to(new_user_session_path)
+ end
+
+ it "redirects to sign in on email change reconfirmation" do
+ # Existing user changing their email — unconfirmed_email triggers reconfirmation detection
+ existing_user = create(:user, confirmed_at: 1.year.ago)
+ existing_user.update_columns(
+ unconfirmed_email: "newemail@example.com",
+ confirmation_token: Devise.friendly_token,
+ confirmation_sent_at: Time.current
+ )
+
+ get user_confirmation_path(confirmation_token: existing_user.confirmation_token)
+
+ expect(response).to redirect_to(new_user_session_path)
+ follow_redirect!
+ expect(response.body).to include("confirmed")
+
+ # Verify email was actually changed
+ existing_user.reload
+ expect(existing_user.email).to eq("newemail@example.com")
+ expect(existing_user.unconfirmed_email).to be_nil
+ end
end
end