Gotcha & workaround when using require_tenant = true with ActionMailer::Preview's
tvongaza opened this issue · 5 comments
There is a small gotcha when using required_tenant = true
alongside ActionMailer::Preview
's. As per the Rails guide (https://guides.rubyonrails.org/action_mailer_basics.html#previewing-emails) a typical action mailer preview looks something like this, where the welcome email will contain calls to a model with a tenant set:
class UserMailerPreview < ActionMailer::Preview
def welcome_email
UserMailer.with(user: User.first).welcome_email
end
end
With acts as tenant we are using this as follows in our dev workflow, which you would expect to properly generate the preview email:
class UserMailerPreview < ActionMailer::Preview
def welcome_email
ActsAsTenant.with_tenant(Account.first) do
UserMailer.with(user: User.first).welcome_email
end
end
end
The call to welcome_email
email will return an ActionMailer::MessageDelivery
object, which is a Delegator and won't actually process the message until the getobj method is called. So what happens in the mail preview is the mail isn't generated within the ActsAsTenant.with_tenant(Account.first)
, but at a later point in time, where the tenant is no longer set, throwing an error - or if for some reason used where another tenant is set - using the wrong tenant.
There is a relatively simple fix, just call .message
in your preview within the ActsAsTenant.with_tenant(Account.first)
:
class UserMailerPreview < ActionMailer::Preview
def welcome_email
ActsAsTenant.with_tenant(Account.first) do
UserMailer.with(user: User.first).welcome_email.message
end
end
end
I've poked through the rails & acts as tenant code a bunch, and unsure of a simple way to fix this. For us it only really impacts us in development so far and the fix is simple enough. It is something to be aware of if using mail previews with the gem.
How come you're not calling with_tenant in the method?
class UserMailerPreview < ActionMailer::Preview
def welcome_email
ActsAsTenant.with_tenant(Account.first) do
UserMailer.with(user: User.first).welcome_email
end
end
end
We are, see the last two code blocks. The first code block is the example from the mail preview docs (https://guides.rubyonrails.org/action_mailer_basics.html#previewing-emails). The next two code blocks are applied with acts as tenant.
You're wrapping ActsAsTenant around the method definitions in your code examples.
🤦 Good catch! Typo, on my end, thanks for the catch (code updated). The issue still exists, as it is still returning a ActionMailer::MessageDelivery
object and not actually performing the mail generation until the __getobj__
call, which in the rail mail preview code will happen later, out of scope of the tenent block.
I can't seem to reproduce this. The following works fine for me in the spec/dummy app.
class UserMailerPreview < ActionMailer::Preview
def welcome_email
ActsAsTenant.with_tenant(Account.first) do
UserMailer.with(user: User.first).welcome_email
end
end
end
The with_tenant
block returns the ActionMailer::Parameterized::MessageDelivery
object returned by welcome_email
and Rails 7 handles that fine.
Added the example in 572469d
Gonna close this, but let me know if you figure out what's different. Maybe a different Rails version or something.