Skip to content

Commit

Permalink
Add a preview interceptor
Browse files Browse the repository at this point in the history
ActionMailer lets us intercept messages before they are delivered or
previewed, this is the ideal time to fetch our preview from the
Notifications API and update the message with it.

Read more in the 'Previewing' section:

https://api.rubyonrails.org/classes/ActionMailer/Base.html
  • Loading branch information
mec committed Apr 19, 2024
1 parent 358e232 commit 68a76f4
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 2 deletions.
1 change: 1 addition & 0 deletions lib/mail/notify.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
require "mail/notify/mailer"
require "mail/notify/message"
require "mail/notify/mail_notify_previews_controller"
require "mail/notify/mail_notify_preview_interceptor"

Mail::Message.include Mail::Notify::Message

Expand Down
4 changes: 2 additions & 2 deletions lib/mail/notify/engine.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# frozen_string_literal: true

require "rails/mailers_controller"

module Mail
module Notify
class Engine < Rails::Engine
initializer "mail-notify.add_delivery_method", before: "action_mailer.set_configs" do
ActionMailer::Base.add_delivery_method(:notify, Mail::Notify::DeliveryMethod)

config.action_mailer.preview_interceptors = [:mail_notify_preview_interceptor]
end
end
end
Expand Down
51 changes: 51 additions & 0 deletions lib/mail/notify/mail_notify_preview_interceptor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# frozen_string_literal: true

##
# This is a ActionMailer interceptor class for previews from the Notifications API
#
# See ActionMailer::Base:
#
# https://github.com/rails/rails/blob/v5.2.8.1/actionmailer/lib/action_mailer/base.rb#L367

class MailNotifyPreviewInterceptor
##
# ActionMailer call back when a preview is being generated.
#
# Transforms the content of the passed in message.

def self.previewing_email(message)
new(message).transform!
end

##
# Creates a new MailNotifyPreviewInterceptor ready for use.

def initialize(message)
@message = message
end

##
# Transforms the content of the message to that from the Notifications API preview.
#
# The html is wrapped in a layout and rendered by the MailNotifyPreviewsControllers renderer.

def transform!
# the messages delivery method will be our Mail::Notify::DeliveryMethod and have the `preview` method.
preview = @message.delivery_method.preview(@message)

@message.subject = preview.subject
@message.html_part.body = renderer.render html: preview.html.html_safe, layout: "govuk_notify_layout"
@message.text_part.body = preview.body

@message
end

private

def renderer
# rendering in Rails without a controller gets far too complicated, instead
# we rely on this empty controller to do it for us.

MailNotifyPreviewsController.renderer
end
end
64 changes: 64 additions & 0 deletions spec/mail/notify/mail_notify_preview_interceptor_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# frozen_string_literal: true

require "rails_helper"

RSpec.describe MailNotifyPreviewInterceptor do
let(:preview_response_double) do
double(
"preview message response",
subject: "Preview subject",
html: "<p>Preview body</p>",
body: "Preview body"
)
end

let(:delivery_method_double) do
double("delivery method", preview: preview_response_double)
end

let(:message_double) do
message = Mail::Message.new(subject: "Original subject")

message.add_part(Mail::Part.new(content_type: "text/html"))
message.add_part(Mail::Part.new(content_type: "text/plain"))

allow(message).to receive(:delivery_method).and_return(delivery_method_double)
message
end

describe ".previewing_email" do
it "transforms the message" do
transformed_message = MailNotifyPreviewInterceptor.previewing_email(message_double)

expect(transformed_message.subject).to eql("Preview subject")
expect(transformed_message.text_part.body.raw_source).to eql("Preview body")
expect(transformed_message.html_part.body).to include("<p>Preview body</p>")
end
end

describe "#transform!" do
it "sets the subject of the message" do
message = message_double

described_class.new(message).transform!

expect(message.subject).to eql preview_response_double.subject
end

it "sets the plain text body of the message" do
message = message_double

described_class.new(message).transform!

expect(message.text_part.body.raw_source).to eql preview_response_double.body
end

it "sets the html body of the message" do
message = message_double

described_class.new(message).transform!

expect(message.html_part.body.raw_source).to include(preview_response_double.html)
end
end
end

0 comments on commit 68a76f4

Please sign in to comment.