Reputation: 3908
I've just set up mailers & action / views alongside HAML gem on my rails app. I'm using transactional email templates provided by mailgun too. A typical mail template in HAML looks something like this:
!!!
%html{xmlns: "http://www.w3.org/1999/xhtml"}
%head
%meta{content: "width=device-width", name: "viewport"}/
%meta{content: "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
%title Alerts e.g. approaching your limit
%link{href: "styles.css", media: "all", rel: "stylesheet", type: "text/css"}/
%body
%table.body-wrap
%tr
%td
%td.container{width: "600"}
.content
%table.main{cellpadding: "0", cellspacing: "0", width: "100%"}
%tr
%td.alert.alert-warning
Warning: You're approaching your limit. Please upgrade.
%tr
%td.content-wrap
%table{cellpadding: "0", cellspacing: "0", width: "100%"}
%tr
%td.content-block
You have
%strong 1 free report
remaining.
%tr
%td.content-block
Add your credit card now to upgrade your account to a premium plan to ensure you don't miss out on any reports.
%tr
%td.content-block
%a.btn-primary{href: "http://www.mailgun.com"} Upgrade my account
%tr
%td.content-block
Thanks for choosing Acme Inc.
.footer
%table{width: "100%"}
%tr
%td.aligncenter.content-block
%a{href: "http://www.mailgun.com"} Unsubscribe
from these alerts.
%td
As you can see it's going to be quite a few lines of code with %html, %head, %tables, %tr, %td etc. repeating on each mail template that I'm going to have on my app (Email confirmation, password_reset, other_notifications, weekly_digests and so on).
My question: Is there a nice RAILS way to dry up all the template code into something like this:
!!!
= render :partial => 'widgets/mail/head'
%body
= render :partial => "widgets/mail/header" # <Mail header>
= yield_mail_content # <Main tag for content>
= render :partial => "widgets/mail/footer" # <Mail footer>
or still better, write registration_confirmation.html.haml as following:
= render :partial => 'widgets/mail/html_above'
= render <!-- registration_mail_specific_content_here -->
= render :partial => 'widgets/mail/html_below'
EDIT: With partials it works, but one still has to maintain HAML nesting of %tables, %tr, %td etc. Like this:
.content
%table.main{cellpadding: "0", cellspacing: "0", width: "100%"}
= render :partial => 'widgets/mail/header'
%tr
%td.content-wrap
%table{cellpadding: "0", cellspacing: "0", width: "100%"}
%tr
%td.content-block
Hi
= succeed ',' do
= @user.first_name.capitalize
This mostly means %table, %tr, %td will continue to remain on every mail template as usual.
Upvotes: 2
Views: 1737
Reputation: 20162
I'll try to describe my current solution for mailer views. Let me know if you have some better ideas.
All the example code will be written in haml
.
Name of the mailer is MainMailer
.
Name of the mailer action is confirmation
.
Create layout template for your mailer inside app/views/layouts/
eg. app/views/layouts/main_mailer.html.haml
Use partials like header
, footer
etc. for elements shared across all mailer actions. These partials has to be placed inside app/views/mailer_name/
directory eg. app/views/main_mailer/
For further DRYing use yield :section_name
eg. yield :top
. Define those yielded sections inside your mailer action template as content_for :section_name do
blocks. (TIP: don't forget to place yield
anywhere in the layout base template, in other case yielded sections won't be displayed)
What is good about this solution is that for new mailer actions it's enough to define one file with sections for yield (like app/views/main_mailer/confirmation.html.haml
). On the other side for the new mailer models you will need to define everything once more (it may be possible to use layout
inside mailer model and specify shared layout there, but I didn't test this).
- content_for :top do
%h1 Some top section text
- content_for :content do
%p.lead Mail content text
%p More of the mail content
-# Main template for all e-mails (like application.html.haml is for views)
!!!
%html{:xmlns => "http://www.w3.org/1999/xhtml"}
%head
%meta{:content => "text/html; charset=utf-8", "http-equiv" => "Content-Type"}/
%meta{:content => "width=device-width", :name => "viewport"}/
= stylesheet_link_tag 'email', media: 'all'
%body
%table.body
%tbody
%tr
%td.center{:align => "center", :valign => "top"}
%center
= render 'header'
-# anywhere use yield in order to use yield :sth blocks
= yield
%table.container
%tbody
%tr
%td
%table.row
%tbody
%tr
%td.wrapper.last
%table.twelve.columns
%tbody
%tr
%td= yield :top
%td.expander
%table.row
%tbody
%tr
%td.wrapper.last
%table.twelve.columns
%tbody
%tr
%td
%br
= yield :content
%td.expander
%table.row.header
%tbody
%tr
%td.center{:align => "center"}
%center
%table.container
%tbody
%tr
%td.wrapper.last
%table.twelve.columns
%tbody
%tr
%td.six.sub-columns.title-area
%h4= link_to @user.service.name, root_url
%td.six.sub-columns.last{:style => "text-align:right; vertical-align:middle;"}
%td.expander
Upvotes: 2