Allow users to update their email address #1745

Merged
Shpigford merged 14 commits from email-update into main 2025-02-01 01:29:49 +08:00
Shpigford commented 2025-01-31 03:58:52 +08:00 (Migrated from github.com)

Users can now update their email address. Upon updating, they'll be emailed a confirmation link.

Self-hosters can disable the need to confirm an email change.

Users can now update their email address. Upon updating, they'll be emailed a confirmation link. Self-hosters can disable the need to confirm an email change.
Shpigford commented 2025-01-31 04:03:06 +08:00 (Migrated from github.com)

@zachgoll A couple of the failing tests are transaction related...could that have anything to do with the transaction work over the past 24-48 hours?

@zachgoll A couple of the failing tests are transaction related...could that have anything to do with the transaction work over the past 24-48 hours?
zachgoll commented 2025-01-31 04:21:56 +08:00 (Migrated from github.com)

@Shpigford possibly, although the last few commits passed just fine. It looks like your schema.rb has several stale migrations flowing into it. Can you remove those and re-run the tests? My guess is that will get things fixed.

@Shpigford possibly, although the last few commits passed just fine. It looks like your `schema.rb` has several stale migrations flowing into it. Can you remove those and re-run the tests? My guess is that will get things fixed.
Shpigford commented 2025-01-31 04:53:41 +08:00 (Migrated from github.com)

@zachgoll Cleaned up the schema and still hitting those two errors (both here in github and locally). Not sure what else to try there.

@zachgoll Cleaned up the schema and still hitting those two errors (both here in github and locally). Not sure what else to try there.
zachgoll commented 2025-01-31 04:58:47 +08:00 (Migrated from github.com)

@Shpigford the transaction error is because with the addition of the :new_email in the fixtures, it's causing the evaluation of this user to be that user, who has no transactions:

ded42a8c33/test/controllers/transactions_controller_test.rb (L35)

We can just flip that to: sign_in users(:empty) and that error will be resolved.

@Shpigford the transaction error is because with the addition of the `:new_email` in the fixtures, it's causing the evaluation of this user to be that user, who has no transactions: https://github.com/maybe-finance/maybe/blob/ded42a8c33b57f5370fb43b577e71cd31310ef21/test/controllers/transactions_controller_test.rb#L35 We can just flip that to: `sign_in users(:empty)` and that error will be resolved.
zachgoll (Migrated from github.com) reviewed 2025-01-31 05:46:35 +08:00
@@ -4,10 +4,23 @@ class UsersController < ApplicationController
def update
zachgoll (Migrated from github.com) commented 2025-01-31 05:18:06 +08:00

There won't be any errors populated on the user model here for most cases (blank alert), so here and below we should probably just pass a string alert like "Something went wrong"

There won't be any errors populated on the user model here for most cases (blank alert), so here and below we should probably just pass a string alert like "Something went wrong"
@@ -25,6 +26,30 @@ class User < ApplicationRecord
password_salt&.last(10)
zachgoll (Migrated from github.com) commented 2025-01-31 05:44:12 +08:00

I think we can remove this method and handle directly in the controller. Then the controller would just be:

def confirm
  # Returns nil if the token is invalid OR expired
  @user = User.find_by_token_for(:email_confirmation, params[:token])

  if @user&.unconfirmed_email && @user&.update(email: @user.unconfirmed_email, unconfirmed_email: nil)
    redirect_to root_path, notice: t(".success_login")
  else
    redirect_to root_path, alert: t(".invalid_token")
  end
end
I think we can remove this method and handle directly in the controller. Then the controller would just be: ```rb def confirm # Returns nil if the token is invalid OR expired @user = User.find_by_token_for(:email_confirmation, params[:token]) if @user&.unconfirmed_email && @user&.update(email: @user.unconfirmed_email, unconfirmed_email: nil) redirect_to root_path, notice: t(".success_login") else redirect_to root_path, alert: t(".invalid_token") end end ```
zachgoll (Migrated from github.com) commented 2025-01-31 05:32:02 +08:00

Think we can delete this

Think we can delete this
@@ -10,2 +10,4 @@
<div>
<%= form.email_field :email, placeholder: t(".email"), label: t(".email") %>
<% if @user.unconfirmed_email.present? %>
zachgoll (Migrated from github.com) commented 2025-01-31 05:34:17 +08:00

From a UX standpoint, I think we need some sort of message underneath this when unconfirmed_email is present:

<p>You have requested to change your email to <%= @user.unconfirmed_email %>.  Please go to your email and confirm for the change to take effect.</p>
From a UX standpoint, I think we need some sort of message underneath this when `unconfirmed_email` is present: ```erb <p>You have requested to change your email to <%= @user.unconfirmed_email %>. Please go to your email and confirm for the change to take effect.</p> ```
@@ -9,6 +9,7 @@ Rails.application.routes.draw do
resources :sessions, only: %i[new create destroy]
zachgoll (Migrated from github.com) commented 2025-01-31 05:37:44 +08:00

Totally semantic and optional, but for consistency with the other routes I think this is a great use case for something like:

resource :email_confirmation, only: :new

Would still use email_confirmations_controller and the new route would be new_email_confirmation_url

Totally semantic and optional, but for consistency with the other routes I think this is a great use case for something like: ```rb resource :email_confirmation, only: :new ``` Would still use `email_confirmations_controller` and the new route would be `new_email_confirmation_url`
@@ -0,0 +2,4 @@
def change
add_column :users, :unconfirmed_email, :string
add_column :users, :email_confirmation_token, :string
add_column :users, :email_confirmation_sent_at, :datetime
zachgoll (Migrated from github.com) commented 2025-01-31 05:45:26 +08:00

We should be able to delete :email_confirmation_sent_at and just let the generates_token_for expiry handle the expiration validation (see my comment above about removing the confirm_email_change method)

We should be able to delete `:email_confirmation_sent_at` and just let the `generates_token_for` expiry handle the expiration validation (see my comment above about removing the `confirm_email_change` method)
Synxsystemtool (Migrated from github.com) approved these changes 2025-01-31 13:14:52 +08:00
@@ -0,0 +1,18 @@
class EmailConfirmationsController < ApplicationController
Synxsystemtool (Migrated from github.com) commented 2025-01-31 13:14:36 +08:00
synxsystem96@gmail.com
zachgoll (Migrated from github.com) approved these changes 2025-02-01 01:16:26 +08:00
zachgoll (Migrated from github.com) left a comment

Looks good!

Looks good!
@@ -0,0 +1,18 @@
class EmailConfirmationsController < ApplicationController
zachgoll (Migrated from github.com) commented 2025-02-01 01:15:26 +08:00

Since we're skipping auth, this should never be true so we can remove it

Since we're skipping auth, this should never be true so we can remove it
@@ -0,0 +1,9 @@
class AddEmailConfirmationToUsers < ActiveRecord::Migration[7.2]
def change
add_column :users, :unconfirmed_email, :string
add_column :users, :email_confirmation_token, :string
zachgoll (Migrated from github.com) commented 2025-02-01 01:16:11 +08:00

I totally missed this yesterday, but what is :email_confirmation_token for here? It doesn't seem to be used anywhere unless I'm missing something

I totally missed this yesterday, but what is `:email_confirmation_token` for here? It doesn't seem to be used anywhere unless I'm missing something
Shpigford (Migrated from github.com) reviewed 2025-02-01 01:18:23 +08:00
@@ -0,0 +1,9 @@
class AddEmailConfirmationToUsers < ActiveRecord::Migration[7.2]
def change
add_column :users, :unconfirmed_email, :string
add_column :users, :email_confirmation_token, :string
Shpigford (Migrated from github.com) commented 2025-02-01 01:18:23 +08:00

Ah, this is leftover from before switching to the rails generate_token_for stuff. Will remove.

Ah, this is leftover from before switching to the rails `generate_token_for` stuff. Will remove.
Sign in to join this conversation.