Skip to content

Commit 809988e

Browse files
authored
Merge pull request #175 from joyofrails/feat/welcome
Add welcome email for new subscribers
2 parents 4a0ce5d + f26680e commit 809988e

27 files changed

+217
-27
lines changed

app/controllers/users/confirmations_controller.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ def update
5353
if @user.confirm!
5454
warden.set_user(@user, scope: :user)
5555

56+
WelcomeNotifier.deliver_to(@user)
57+
5658
redirect_to users_dashboard_path, notice: "Thank you for confirming your email address"
5759
else
5860
redirect_to new_users_confirmation_path, alert: "Something went wrong"

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/jobs/notifications/event_job.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ class Notifications::EventJob < ApplicationJob
44
def perform(event)
55
# Enqueue individual deliveries
66
event.notifications.each do |notification|
7-
event.deliver_notification(notification)
7+
notification.transaction do
8+
event.deliver_notification(notification)
9+
notification.touch(:processed_at)
10+
end
811
end
912
end
1013
end

app/lib/warden_extensions/setup.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ def configure_manager
2222
case auth.winning_strategy&.key
2323
when :magic_session
2424
user.confirm!
25+
WelcomeNotifier.deliver_to(user)
2526
when :password
2627
# no op
2728
else # nil, as with test helpers

app/mailers/emails/user_mailer.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,11 @@ def password_reset(user, password_reset_token)
1919

2020
mail to: @user.email, subject: "Reset your password"
2121
end
22+
23+
def welcome(user, unsubscribe_token = :no_token)
24+
@user = user
25+
@unsubscribe_token = unsubscribe_token
26+
27+
mail to: @user.email, subject: "Welcome to Joy of Rails!"
28+
end
2229
end

app/models/notification.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@ class Notification < ApplicationRecord
55
scope :newest_first, -> { order(created_at: :desc) }
66

77
delegate :params, :record, to: :event
8+
9+
scope :processed, -> { where.not(processed_at: nil) }
810
end

app/models/notification_event.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,22 @@ def self.inherited(notifier)
2929
notifier.const_set :Notification, Class.new(Notification)
3030
end
3131

32+
def deliver_to?(recipient)
33+
true
34+
end
35+
3236
# CommentNotifier.deliver(User.all)
3337
# CommentNotifier.deliver(User.all, priority: 10)
3438
# CommentNotifier.deliver(User.all, queue: :low_priority)
3539
# CommentNotifier.deliver(User.all, wait: 5.minutes)
3640
# CommentNotifier.deliver(User.all, wait_until: 1.hour.from_now)
37-
def deliver(recipients = nil, enqueue_job: true, **options)
41+
def deliver(given_recipients = nil, enqueue_job: true, **options)
3842
validate!
3943

44+
recipients = Array.wrap(given_recipients)
45+
4046
transaction do
41-
recipients_attributes = Array.wrap(recipients).map do |recipient|
47+
recipients_attributes = recipients.map do |recipient|
4248
recipient_attributes_for(recipient)
4349
end
4450

app/models/user.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ class User < ApplicationRecord
88

99
has_one :newsletter_subscription, as: :subscriber, dependent: :destroy
1010

11+
scope :recently_confirmed, -> { where("confirmed_at > ?", 2.weeks.ago) }
12+
1113
accepts_nested_attributes_for :email_exchanges, limit: 1
1214

1315
validates :email, presence: true, uniqueness: true, format: {with: URI::MailTo::EMAIL_REGEXP}

app/notifiers/welcome_notifier.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
class WelcomeNotifier < NotificationEvent
2+
def self.deliver_to(user, **)
3+
new(params: {user: user}).deliver(user, **)
4+
end
5+
6+
def deliver_notification(notification)
7+
user = notification.recipient
8+
unsubscribe_token = user&.newsletter_subscription&.generate_token_for(:unsubscribe) || :no_token
9+
10+
if !deliver_to?(user)
11+
Rails.logger.info "#[#{self.class}] Skipping delivery for: #{user.class.name}##{user.id}"
12+
Honeybadger.event("empty_notification", notifier: self.class.name, recipient: "#{user.class.name}##{user.id}")
13+
return false
14+
end
15+
16+
Emails::UserMailer.welcome(user, unsubscribe_token).deliver_later
17+
end
18+
19+
def deliver_to?(recipient)
20+
Notification.processed.joins(:notification_event).where(recipient: recipient, notification_event: {type: self.class.name}).count < 1
21+
end
22+
end

app/views/emails/magic_session_mailer/no_account_found.text.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Is this the right email?
1+
# Is this the right email?
22

33
It looks like there isn’t an account on test tied to this email address.
44

0 commit comments

Comments
 (0)