Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor MJML layout/template support #33

Merged
merged 1 commit into from
Jul 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ source 'https://rubygems.org'

gemspec

gem 'rails', '4.2.6'
gem 'rails', '~> 5.2'
gem 'byebug'

group :development do
# gem 'guard' # NOTE: this is necessary in newer versions
Expand Down
137 changes: 76 additions & 61 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6,93 +6,104 @@ PATH
GEM
remote: https://rubygems.org/
specs:
actionmailer (4.2.6)
actionpack (= 4.2.6)
actionview (= 4.2.6)
activejob (= 4.2.6)
actioncable (5.2.0)
actionpack (= 5.2.0)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailer (5.2.0)
actionpack (= 5.2.0)
actionview (= 5.2.0)
activejob (= 5.2.0)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 1.0, >= 1.0.5)
actionpack (4.2.6)
actionview (= 4.2.6)
activesupport (= 4.2.6)
rack (~> 1.6)
rack-test (~> 0.6.2)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-dom-testing (~> 2.0)
actionpack (5.2.0)
actionview (= 5.2.0)
activesupport (= 5.2.0)
rack (~> 2.0)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (4.2.6)
activesupport (= 4.2.6)
actionview (5.2.0)
activesupport (= 5.2.0)
builder (~> 3.1)
erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
activejob (4.2.6)
activesupport (= 4.2.6)
globalid (>= 0.3.0)
activemodel (4.2.6)
activesupport (= 4.2.6)
builder (~> 3.1)
activerecord (4.2.6)
activemodel (= 4.2.6)
activesupport (= 4.2.6)
arel (~> 6.0)
activesupport (4.2.6)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
activejob (5.2.0)
activesupport (= 5.2.0)
globalid (>= 0.3.6)
activemodel (5.2.0)
activesupport (= 5.2.0)
activerecord (5.2.0)
activemodel (= 5.2.0)
activesupport (= 5.2.0)
arel (>= 9.0)
activestorage (5.2.0)
actionpack (= 5.2.0)
activerecord (= 5.2.0)
marcel (~> 0.3.1)
activesupport (5.2.0)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
arel (6.0.4)
arel (9.0.0)
builder (3.2.3)
byebug (10.0.2)
concurrent-ruby (1.0.5)
crass (1.0.4)
erubis (2.7.0)
erubi (1.7.1)
globalid (0.4.1)
activesupport (>= 4.2.0)
i18n (0.9.5)
i18n (1.0.1)
concurrent-ruby (~> 1.0)
json (1.8.6)
loofah (2.2.2)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.0)
mini_mime (>= 0.1.1)
marcel (0.3.2)
mimemagic (~> 0.3.2)
metaclass (0.0.4)
method_source (0.9.0)
mimemagic (0.3.2)
mini_mime (1.0.0)
mini_portile2 (2.3.0)
minitest (5.11.3)
mocha (1.4.0)
metaclass (~> 0.0.1)
nokogiri (1.8.2)
nio4r (2.3.1)
nokogiri (1.8.4)
mini_portile2 (~> 2.3.0)
rack (1.6.10)
rack-test (0.6.3)
rack (>= 1.0)
rails (4.2.6)
actionmailer (= 4.2.6)
actionpack (= 4.2.6)
actionview (= 4.2.6)
activejob (= 4.2.6)
activemodel (= 4.2.6)
activerecord (= 4.2.6)
activesupport (= 4.2.6)
bundler (>= 1.3.0, < 2.0)
railties (= 4.2.6)
sprockets-rails
rails-deprecated_sanitizer (1.0.3)
activesupport (>= 4.2.0.alpha)
rails-dom-testing (1.0.9)
activesupport (>= 4.2.0, < 5.0)
nokogiri (~> 1.6)
rails-deprecated_sanitizer (>= 1.0.1)
rack (2.0.5)
rack-test (1.0.0)
rack (>= 1.0, < 3)
rails (5.2.0)
actioncable (= 5.2.0)
actionmailer (= 5.2.0)
actionpack (= 5.2.0)
actionview (= 5.2.0)
activejob (= 5.2.0)
activemodel (= 5.2.0)
activerecord (= 5.2.0)
activestorage (= 5.2.0)
activesupport (= 5.2.0)
bundler (>= 1.3.0)
railties (= 5.2.0)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.0.4)
loofah (~> 2.2, >= 2.2.2)
railties (4.2.6)
actionpack (= 4.2.6)
activesupport (= 4.2.6)
railties (5.2.0)
actionpack (= 5.2.0)
activesupport (= 5.2.0)
method_source
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (12.3.1)
sprockets (3.7.1)
sprockets (3.7.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.1)
Expand All @@ -103,14 +114,18 @@ GEM
thread_safe (0.3.6)
tzinfo (1.2.5)
thread_safe (~> 0.1)
websocket-driver (0.7.0)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.3)

PLATFORMS
ruby

DEPENDENCIES
byebug
mjml-rails!
mocha (= 1.4.0)
rails (= 4.2.6)
rails (~> 5.2)

BUNDLED WITH
1.16.1
1.16.2
70 changes: 29 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
An example template might look like:

```erb
<!-- ./app/views/user_mailer/email.mjml -->
<!-- ./app/views/user_mailer/email.html.mjml -->
<mjml>
<mj-head>
<mj-preview>Hello World</mj-preview>
Expand All @@ -16,7 +16,7 @@ An example template might look like:
<mj-section>
<mj-column>
<mj-text>Hello World</mj-text>
<%= render :partial => 'info', :formats => [:html] %>
<%= render partial: "info" %>
</mj-column>
</mj-section>
</mj-body>
Expand All @@ -26,19 +26,19 @@ An example template might look like:
And the partial `_info.mjml`:

```erb
<!-- ./app/views/user_mailer/_info.mjml -->
<!-- ./app/views/user_mailer/_info.html.erb -->
<mj-text>This is <%= @user.username %></mj-text>
```

* Notice you can use ERb and partials inside the template.
* Notice you can use ERB and partials inside the template.

Your `user_mailer.rb` might look like this::

```ruby
# ./app/mailers/user_mailer.rb
class UserMailer < ActionMailer::Base
def user_signup_confirmation()
mail(to: 'test@example.com', subject: 'test') do |format|
def user_signup_confirmation
mail(to: "user@example.com", from: "app@example.com") do |format|
format.text
format.mjml
end
Expand Down Expand Up @@ -118,65 +118,53 @@ npm install -g mjml@3.3.5

Mailer:
```ruby
# mailers/foo_mailer.rb
# mailers/my_mailer.rb
class MyMailer < ActionMailer::Base
layout "default"

def mail_template(template_name, recipient, subject, **params)
mail(
to: recipient.email,
from: ENV["MAILER_FROM"],
subject: subject
) do |format|
format.mjml { render template_name, locals: { recipient: recipient }.merge(params) }
end
end
def foo_bar(user)
@recipient = user

# this function is called to send the email
def foo(item, user)
mail_template(
"foo_bar",
user,
"email subject",
request: item
)
mail(to: user.email, from: "app@example.com") do |format|
format.html
end
end
end
```

Email layout:
```html
<!-- views/layouts/default.mjml -->
<!-- views/layouts/default.html.mjml -->
<mjml>
<mj-body>
<%= yield %>
</mj-body>
<mj-body>
<%= yield %>
</mj-body>
</mjml>
```

Email view:
```html
<!-- views/my_mailer/foo_bar.mjml.erb -->
<%= render partial: "to", formats: [:html], locals: { name: recipient.name } %>
<!-- views/my_mailer/foo_bar.html.erb -->
<%= render partial: "to" %>

<mj-section>
<mj-column>
<mj-text>
Hello <%= recipient.name %>!
</mj-text>
</mj-column>
<mj-column>
<mj-text>
Something foo regarding bar!
</mj-text>
</mj-column>
</mj-section>
```

Email partial:
```html
<!-- views/my_mailer/_to.mjml -->
<!-- views/my_mailer/_to.html.erb -->
<mj-section>
<mj-column>
<mj-text>
<%= name %>,
</mj-text>
</mj-column>
<mj-column>
<mj-text>
Hello <%= @recipient.name %>,
</mj-text>
</mj-column>
</mj-section>
```

Expand Down
15 changes: 13 additions & 2 deletions lib/generators/mjml/mailer/mailer_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ module Generators
class MailerGenerator < Erb::Generators::MailerGenerator
source_root File.expand_path("../templates", __FILE__)

protected
private

def format
nil # Our templates have no format
:html
end

def formats
Expand All @@ -18,6 +18,17 @@ def formats
def handler
:mjml
end

def view_handler
Mjml.template_language
end

def filename_with_extensions(name, file_format = format)
# Due to MJML single-pass processing nature
# layout files MUST have .mjml extension, but views/templates cannot
is_layout_file = name.in?([:layout, "mailer"])
[name, file_format, is_layout_file ? handler : view_handler].compact.join(".")
end
end
end
end
5 changes: 5 additions & 0 deletions lib/generators/mjml/mailer/templates/layout.html.mjml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<mjml>
<mj-body>
<%%= yield %>
</mj-body>
</mjml>
1 change: 0 additions & 1 deletion lib/generators/mjml/mailer/templates/layout.mjml

This file was deleted.

10 changes: 9 additions & 1 deletion lib/mjml.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,15 @@ def template_handler

def call(template)
compiled_source = template_handler.call(template)
if template.formats.include?(:mjml)

# Per MJML v4 syntax documentation[0] valid/render'able document MUST start with <mjml> root tag
# If we get here and template source doesn't start with one it means
# that we are rendering partial named according to legacy naming convention (partials ending with '.mjml')
# Therefore we skip MJML processing and return raw compiled source. It will be processed
# by MJML library when top-level layout/template is rendered
#
# [0] - https://github.com/mjmlio/mjml/blob/master/doc/guide.md#mjml
if template.source =~ /<mjml>/
"Mjml::Mjmltemplate.to_html(begin;#{compiled_source};end).html_safe"
else
compiled_source
Expand Down
Loading