Preview emails for any user with Rails 4.1
Last night I was preparing a weekly email to remind my dear TimeSampler users about the work they have done in their previous week.
I started by adding a couple of previews one for the user that has actual stuff done (see an example below):
Setup a mailer (you can skip this)
The first thing you need to preview an email is to have a Mailer (yuk!), here's a simple one:
# app/mailers/user_notifier class UserNotifier < ActionMailer::Base default from: '[email protected]', reply_to: '[email protected]' helper DayHelper def weekly_report user @user = user @project_days = project_days @days = project_days.group_by(&:day).to_a.sort @end_time = end_time @start_time = start_time mail to: user.email, subject: "TimeSampler: Weekly activity report · week #{start_time.cweek}" end end
And its view:
/ app/views/user_notifier = render 'style' %h1 TimeSampler: Weekly activity report · week #{@start_time.cweek} %p Hi #{@user.some_name}! - if @project_days.any? %p Here's what you've done during the past week (#{link_to "from #{@start_time} to #{@end_time}", journal_path}): .days - @days.sort.reverse.each do |(day, project_days)| = render 'day', day: day, project_days: project_days - else = render 'blank_slate' = render 'footer'
Setup a previewer
Then we need to add our previewer. Problem is that the default location for the previewers is test/mailers/previews and as you may have guessed already we have no test dir in this app, instead we'll put our ActionMailer::Preview classes inside app/mailer_previews.
To do that let's add the following line to config/environments/development:
Rails.application.configure do # … config.action_mailer.preview_path = "#{Rails.root}/app/mailer_previews" end
Your previewer could be something like this:
class UserNotifierPreview < ActionMailer::Preview def weekly_report_empty UserNotifier.weekly_report(andrea) end def weekly_report_full UserNotifier.weekly_report(elia) end # …s end
And have beautyful previews for your emails. For example, this is how the blankslate TimeSampler mail looks like:
POWER PREVIEWING !!1!
Now what if you want to preview emails for arbitrary users without having to manually update the code?
No problem, luckly it's Ruby! After a bit of inspection inside actionmailer and railties I found the right hook…
Rails asks the previewer if an email_exists? before trying to display it, so we'll hook into that method and auto-define a previewer instance method for each user in out system (please don't try this with more than a hundred users).
Here teh codez:
class UserNotifierPreview < ActionMailer::Preview def self.email_exists?(*) User.all.each do |user| next if user.email.blank? email = user.email.gsub(/\W/, '_') method_name = "weekly_report_#{email}" user_id = user.id define_method method_name do UserNotifier.weekly_report(User.find(user_id)) end end super end # … end
Of course it's advisable to be careful and probably reduce the set of users you're gonna prepare a preview method for. In my case the development database is quite manageable and hence User.all is fine.
Final Pro-tip
You find cumbersome to dig the sources of the gems in your bundle even if you setup the $EDITOR var in your bash and are a regular client of bundle open <my-gem>?
Then you can give a try to the Bundler bundle for TextMate2 which will give you an incredible speed boost while perusing the gems in your current Gemfile.lock.
To get some more info on my TextMate2 setup you can read:
Read next: Pimp my TextMate2 — Ruby edition










