Skip to content

Commit bf08cf9

Browse files
committed
Ensure welcome email unsubscribe works as expected
1 parent f2b3a01 commit bf08cf9

File tree

9 files changed

+64
-23
lines changed

9 files changed

+64
-23
lines changed

app/controllers/users/newsletter_subscriptions_controller.rb

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,29 +65,42 @@ def subscribe
6565
end
6666

6767
def unsubscribe
68-
if params[:token]
69-
subscription = NewsletterSubscription.find_by_token_for(:unsubscribe, params[:token]) or raise ActiveRecord::RecordNotFound
70-
subscription.destroy
71-
elsif current_user
72-
# Even though we model the subscription as a has_one, we should destroy
73-
# all because has_one is not enforced as a constraint
74-
NewsletterSubscription.where(subscriber: current_user).destroy_all
75-
else
76-
not_found!
77-
end
68+
subscriber = find_subscriber
69+
70+
# Even though we model the subscription as a has_one, we should destroy
71+
# all because has_one is not enforced as a constraint
72+
NewsletterSubscription.where(subscriber: subscriber).destroy_all
73+
74+
notice = "You have been unsubscribed from the Joy of Rails newsletter"
7875

7976
if request.post? && params["List-Unsubscribe"] == "One-Click"
8077
# must not redirect according to RFC 8058
8178
# could render show action instead
82-
render plain: "You have been unsubscribed", status: :ok
79+
render plain: notice, status: :ok
8380
else
8481
respond_to do |format|
85-
format.html { redirect_to root_path, notice: "You have been unsubscribed" }
82+
format.html { redirect_to root_path, notice: notice }
8683
format.turbo_stream {
8784
redirect_path = current_user ? users_newsletter_subscriptions_path : new_users_newsletter_subscription_path
8885
redirect_to redirect_path
8986
}
9087
end
9188
end
9289
end
90+
91+
private
92+
93+
def find_subscriber
94+
subscriber = if params[:token]
95+
subscription = NewsletterSubscription.find_by_token_for!(:unsubscribe, params[:token])
96+
subscription&.subscriber
97+
else
98+
current_user
99+
end
100+
101+
subscriber or raise ActiveRecord::RecordNotFound
102+
rescue ActiveSupport::MessageVerifier::InvalidSignature
103+
Honeybadger.event("invalid_token", {path: request.path, controller: self.class.name, action: action_name})
104+
raise ActiveRecord::RecordNotFound
105+
end
93106
end

app/mailers/emails/user_mailer.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ def password_reset(user, password_reset_token)
2020
mail to: @user.email, subject: "Reset your password"
2121
end
2222

23-
def welcome(user)
23+
def welcome(user, unsubscribe_token = :no_token)
2424
@user = user
25+
@unsubscribe_token = unsubscribe_token
2526

2627
mail to: @user.email, subject: "Welcome to Joy of Rails!"
2728
end

app/notifiers/welcome_notifier.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ def self.deliver_to(user, **)
55

66
def deliver_notification(notification)
77
user = notification.recipient
8+
unsubscribe_token = user&.newsletter_subscription&.generate_token_for(:unsubscribe) || :no_token
89

910
if !deliver_to?(user)
1011
Rails.logger.info "#[#{self.class}] Skipping delivery for: #{user.class.name}##{user.id}"
1112
Honeybadger.event("empty_notification", notifier: self.class.name, recipient: "#{user.class.name}##{user.id}")
1213
return false
1314
end
1415

15-
Emails::UserMailer.welcome(user).deliver_later
16+
Emails::UserMailer.welcome(user, unsubscribe_token).deliver_later
1617
end
1718

1819
def deliver_to?(recipient)

app/views/emails/user_mailer/welcome.html.erb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
<p>If you’re into RSS, you may want to subscribe to the <%= link_to "Joy of Rails feed", feed_index_url %>.</p>
88

9-
<p>You can also <%= link_to "unsubscribe", unsubscribe_users_newsletter_subscriptions_url %> at any time. That’s ok too!</p>
9+
<% unless @unsubscribe_token == :no_token %>
10+
<p>You can also <%= link_to "unsubscribe", unsubscribe_users_newsletter_subscription_url(@unsubscribe_token) %> at any time. That’s ok too!</p>
11+
<% end %>
1012

1113
<p>If you have any questions, feedback, or just want to say hi, please don’t hesitate to reach out. I’d love to hear from you.</p>
1214

app/views/emails/user_mailer/welcome.text.erb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ Now that you’ve joined, you can expect occasional email updates from me. I’m
66

77
If you’re into RSS, you may want to subscribe to the Joy of Rails feed: <%= feed_index_url %>.
88

9-
You can also unsubscribe at any time: <%= unsubscribe_users_newsletter_subscriptions_url %>. That’s ok too!
9+
<% unless @unsubscribe_token == :no_token %>
10+
You can also unsubscribe at any time: <%= unsubscribe_users_newsletter_subscription_url(@unsubscribe_token) %>. That’s ok too!
11+
<% end %>
1012

1113
If you have any questions, feedback, or just want to say hi, please don’t hesitate to reach out. I’d love to hear from you.
1214

spec/mailers/previews/emails/user_mailer_preview.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ def password_reset
1010
end
1111

1212
def welcome
13-
Emails::UserMailer.welcome(FactoryBot.build(:user))
13+
Emails::UserMailer.welcome(FactoryBot.build(:user), "unsubscribe_token")
1414
end
1515
end

spec/notifiers/welcome_notifier_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
WelcomeNotifier.deliver_to(user)
1313
perform_enqueued_jobs
1414

15-
expect(Emails::UserMailer).to have_received(:welcome).with(user).once
15+
expect(Emails::UserMailer).to have_received(:welcome).with(user, :no_token).once
1616
end
1717
end
1818
end

spec/requests/users/newsletter_subscriptions_spec.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@
233233
user.reload
234234

235235
expect(response).to redirect_to(root_path)
236-
expect(flash[:notice]).to eq("You have been unsubscribed")
236+
expect(flash[:notice]).to eq("You have been unsubscribed from the Joy of Rails newsletter")
237237

238238
expect(user.newsletter_subscription).to be_nil
239239
end
@@ -249,7 +249,7 @@
249249
user.reload
250250

251251
expect(response).to redirect_to(root_path)
252-
expect(flash[:notice]).to eq("You have been unsubscribed")
252+
expect(flash[:notice]).to eq("You have been unsubscribed from the Joy of Rails newsletter")
253253

254254
expect(user.newsletter_subscription).to be_nil
255255
end
@@ -265,7 +265,7 @@
265265
user.reload
266266

267267
expect(response).to redirect_to(root_path)
268-
expect(flash[:notice]).to eq("You have been unsubscribed")
268+
expect(flash[:notice]).to eq("You have been unsubscribed from the Joy of Rails newsletter")
269269

270270
expect(user.newsletter_subscription).to be_nil
271271
end
@@ -291,7 +291,7 @@
291291
expect(user.newsletter_subscription).to be_present
292292

293293
expect {
294-
post unsubscribe_users_newsletter_subscription_path(user.newsletter_subscription.id)
294+
post unsubscribe_users_newsletter_subscription_path("bad-token")
295295
}.not_to change(NewsletterSubscription, :count)
296296

297297
user.reload
@@ -313,7 +313,7 @@
313313
user.reload
314314

315315
expect(response).to redirect_to(root_path)
316-
expect(flash[:notice]).to eq("You have been unsubscribed")
316+
expect(flash[:notice]).to eq("You have been unsubscribed from the Joy of Rails newsletter")
317317

318318
expect(user.newsletter_subscription).to be_nil
319319
end

spec/system/users/confirmations_spec.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,26 @@
2626
expect(page).to have_content("Thank you for confirming your email address")
2727
expect(User.last).to be_confirmed
2828
end
29+
30+
it "sends welcome email which allow user to unsubscribe" do
31+
user = FactoryBot.create(:user, :subscriber)
32+
user.generate_token_for(:confirmation)
33+
34+
visit edit_users_confirmation_path(user.generate_token_for(:confirmation))
35+
36+
click_button "Confirm email"
37+
38+
expect(user.reload.newsletter_subscription).to be_present
39+
40+
perform_enqueued_jobs_and_subsequently_enqueued_jobs
41+
42+
mail = find_mail_to(user.email)
43+
44+
expect(mail.subject).to eq "Welcome to Joy of Rails!"
45+
46+
visit email_link(mail, "unsubscribe")
47+
48+
expect(page).to have_content("You have been unsubscribed from the Joy of Rails newsletter")
49+
expect(user.reload.newsletter_subscription).to be_nil
50+
end
2951
end

0 commit comments

Comments
 (0)