From ec0e84664f0c3516a3232758b4ec56c3a6d369e5 Mon Sep 17 00:00:00 2001 From: jbranchaud Date: Mon, 6 Oct 2025 08:52:25 -0500 Subject: [PATCH] Add Prevent Mailer Previews From Cluttering Database as a Rails TIL --- README.md | 3 +- ...ailer-previews-from-cluttering-database.md | 50 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 rails/prevent-mailer-previews-from-cluttering-database.md diff --git a/README.md b/README.md index 07e866f..b143e7c 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ pairing with smart people at Hashrocket. For a steady stream of TILs, [sign up for my newsletter](https://crafty-builder-6996.ck.page/e169c61186). -_1659 TILs and counting..._ +_1660 TILs and counting..._ See some of the other learning resources I work on: - [Get Started with Vimium](https://egghead.io/courses/get-started-with-vimium~3t5f7) @@ -1103,6 +1103,7 @@ If you've learned something here, support my efforts writing daily TILs by - [Polymorphic Path Helpers](rails/polymorphic-path-helpers.md) - [Prefer select_all Over execute For Read Queries](rails/prefer-select-all-over-execute-for-read-queries.md) - [Pretend Generations](rails/pretend-generations.md) +- [Prevent Mailer Previews From Cluttering Database](rails/prevent-mailer-previews-from-cluttering-database.md) - [Prevent Writes With A Sandboxed Rails Console](rails/prevent-writes-with-a-sandboxed-rails-console.md) - [Provide Fake Form Helper To Controllers](rails/provide-fake-form-helper-to-controllers.md) - [Query A Single Value From The Database](rails/query-a-single-value-from-the-database.md) diff --git a/rails/prevent-mailer-previews-from-cluttering-database.md b/rails/prevent-mailer-previews-from-cluttering-database.md new file mode 100644 index 0000000..25d450e --- /dev/null +++ b/rails/prevent-mailer-previews-from-cluttering-database.md @@ -0,0 +1,50 @@ +# Prevent Mailer Previews From Cluttering Database + +ActionMailer Previews give you a way to view email templates that your system +sends. This is how I check that it is styled properly and that the logic and +data of the template are able to run and render. + +Data for a preview typically means we need ActiveRecord objects and even their +associations. If we start creating one-off records in our previews either with +`#create` or with something like `FactoryBot`, those records will get left +behind in our development database. Every view and refresh of a preview will +generate more of these records. + +One way to get around that is to use `#new` and `#build`. I've found this +cumbersome and it often leaves assocations missing or inaccessible. + +What if instead the preview could clean up after itself? That sounds like a +great job for a database transaction. + +Let's create a `test/mailers/previews/base_preview.rb` as a base class for all +our preview classes. + +```ruby +class BasePreview < ActionMailer::Preview + def self.call(...) + message = nil + ActiveRecord::Base.transaction do + message = super(...) + raise ActiveRecord::Rollback + end + message + end +end +``` + +This wraps the existing `self.call` functionality in a transaction that +collects the resulting message from the preview and then rolls back the +database changes. + +Now, instead of our individual preview classes inheriting directly from +`ActionMailer::Preview`, they can inherit from `BasePreview`. + +```ruby +class UserMailer < BasePreview + + # ... + +end +``` + +[source](https://stackoverflow.com/a/31289295)