Skip to content

Commit

Permalink
Merge rodauth:mailer into rodauth:install
Browse files Browse the repository at this point in the history
There is no good reason why mailer generation should happen separately
from the rodauth:install generator, because the user will always want to
override default email templates, and we want to encourage them to do
so. Using an Action Mailer class is a standard Rails way to do so.

So, we create the mailer and templates in rodauth:install generator,
and remove the rodauth:mailer generator. If the user is using a
3rd-party service for sending emails, they will just replace the mailer
with their code. In any case, that's easier for them to do when they see
the default email templates.
  • Loading branch information
janko committed Mar 21, 2021
1 parent 82dcc3d commit 7890515
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 143 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## HEAD

* Create `RodauthMailer` and email templates in `rodauth:install`, and remove `rodauth:mailer` (@janko)

* Raise `KeyError` in `#rodauth` method when the Rodauth instance doesn't exist (@janko)

* Add `Rodauth::Rails.authenticated` routing constraint for requiring authentication (@janko)
Expand Down
92 changes: 48 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ The generator will create the following files:
* Rodauth app at `app/lib/rodauth_app.rb`
* Rodauth controller at `app/controllers/rodauth_controller.rb`
* Account model at `app/models/account.rb`
* Rodauth mailer at `app/mailers/rodauth_mailer.rb` with views

### Migration

Expand Down Expand Up @@ -211,6 +212,23 @@ class Account < ApplicationRecord
end
```

### Rodauth mailer

The default Rodauth app is configured to use `RodauthMailer` mailer
for sending authentication emails.

```rb
# app/mailers/rodauth_mailer.rb
class RodauthMailer < ApplicationMailer
def verify_account(recipient, email_link) ... end
def reset_password(recipient, email_link) ... end
def verify_login_change(recipient, old_login, new_login, email_link) ... end
def password_changed(recipient) ... end
# def email_auth(recipient, email_link) ... end
# def unlock_account(recipient, email_link) ... end
end
```
## Usage
### Routes
Expand Down Expand Up @@ -443,54 +461,33 @@ end

### Mailer

Depending on the features you've enabled, Rodauth may send emails as part of
the authentication flow. Most email settings can be customized:
The install generator will create `RodauthMailer` with default email templates,
and configure Rodauth features that send emails as part of the authentication
flow to use it.

```rb
# app/lib/rodauth_app.rb
class RodauthApp < Rodauth::Rails::App
# ...
configure do
# app/mailers/rodauth_mailer.rb
class RodauthMailer < ApplicationMailer
def verify_account(recipient, email_link)
# ...
# general settings
email_from "[email protected]"
email_subject_prefix "[MyApp] "
send_email(&:deliver_later)
end
def reset_password(recipient, email_link)
# ...
# feature settings
verify_account_email_subject "Verify your account"
verify_account_email_body { "Verify your account by visting this link: #{verify_account_email_link}" }
end
def verify_login_change(recipient, old_login, new_login, email_link)
# ...
end
def password_changed(recipient)
# ...
end
# def email_auth(recipient, email_link)
# ...
# end
# def unlock_account(recipient, email_link)
# ...
# end
end
```

This is convenient when starting out, but eventually you might want to use your
own mailer. You can start by running the following command:

```sh
$ rails generate rodauth:mailer
```

This will create a `RodauthMailer` with the associated mailer views in
`app/views/rodauth_mailer` directory:

```rb
# app/mailers/rodauth_mailer.rb
class RodauthMailer < ApplicationMailer
def verify_account(recipient, email_link) ... end
def reset_password(recipient, email_link) ... end
def verify_login_change(recipient, old_login, new_login, email_link) ... end
def password_changed(recipient) ... end
# def email_auth(recipient, email_link) ... end
# def unlock_account(recipient, email_link) ... end
end
```
You can then uncomment the lines in your Rodauth configuration to have it call
your mailer. If you've enabled additional authentication features that send
emails, make sure to override their `create_*_email` methods as well.
```rb
# app/lib/rodauth_app.rb
class RodauthApp < Rodauth::Rails::App
Expand Down Expand Up @@ -524,10 +521,17 @@ class RodauthApp < Rodauth::Rails::App
end
```

This approach can be used even if you're using a 3rd-party service for
transactional emails, where emails are sent via HTTP instead of SMTP. Whatever
the `create_*_email` block returns will be passed to `send_email`, so you can
be creative.
The above configuration uses `#deliver_later`, which assumes Active Job is
configured. It's generally recommended to send emails in a background job,
for better throughput and ability to retry. However, if you want to send emails
synchronously, you can modify the code to call `#deliver` instead.
The `#send_email` method will receive whatever object is returned by the
`#create_*_email` methods. But if that doesn't suit you, you can override
`#send_*_email` methods instead, which are expected to send the email
immediately. This might work better in scenarios such as using a 3rd-party
service for transactional emails, where emails are sent via HTTP instead of
SMTP.

### Migrations

Expand Down
17 changes: 17 additions & 0 deletions lib/generators/rodauth/install_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ class InstallGenerator < ::Rails::Generators::Base
include ::ActiveRecord::Generators::Migration
include MigrationHelpers

MAILER_VIEWS = %w[
email_auth
password_changed
reset_password
unlock_account
verify_account
verify_login_change
]

source_root "#{__dir__}/templates"
namespace "rodauth:install"

Expand Down Expand Up @@ -47,6 +56,14 @@ def create_account_model
template "app/models/account.rb"
end

def create_mailer
template "app/mailers/rodauth_mailer.rb"

MAILER_VIEWS.each do |view|
template "app/views/rodauth_mailer/#{view}.text.erb"
end
end

private

def sequel_uri_scheme
Expand Down
37 changes: 0 additions & 37 deletions lib/generators/rodauth/mailer_generator.rb

This file was deleted.

48 changes: 21 additions & 27 deletions lib/generators/rodauth/templates/app/lib/rodauth_app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,35 +58,29 @@ class RodauthApp < Rodauth::Rails::App
# already_logged_in { redirect login_redirect }
# ==> Emails
# Uncomment the lines below once you've imported mailer views.
# create_reset_password_email do
# RodauthMailer.reset_password(email_to, reset_password_email_link)
# Use a custom mailer for delivering authentication emails.
create_reset_password_email do
RodauthMailer.reset_password(email_to, reset_password_email_link)
end
create_verify_account_email do
RodauthMailer.verify_account(email_to, verify_account_email_link)
end
create_verify_login_change_email do |login|
RodauthMailer.verify_login_change(login, verify_login_change_old_login, verify_login_change_new_login, verify_login_change_email_link)
end
create_password_changed_email do
RodauthMailer.password_changed(email_to)
end
# create_email_auth_email do
# RodauthMailer.email_auth(email_to, email_auth_email_link)
# end
# create_verify_account_email do
# RodauthMailer.verify_account(email_to, verify_account_email_link)
# create_unlock_account_email do
# RodauthMailer.unlock_account(email_to, unlock_account_email_link)
# end
# create_verify_login_change_email do |login|
# RodauthMailer.verify_login_change(login, verify_login_change_old_login, verify_login_change_new_login, verify_login_change_email_link)
# end
# create_password_changed_email do
# RodauthMailer.password_changed(email_to)
# end
# # create_email_auth_email do
# # RodauthMailer.email_auth(email_to, email_auth_email_link)
# # end
# # create_unlock_account_email do
# # RodauthMailer.unlock_account(email_to, unlock_account_email_link)
# # end
# send_email do |email|
# # queue email delivery on the mailer after the transaction commits
# db.after_commit { email.deliver_later }
# end
# In the meantime, you can tweak settings for emails created by Rodauth.
# email_subject_prefix "[MyApp] "
# email_from "noreply@myapp.com"
# send_email(&:deliver_later)
# reset_password_email_body { "Click here to reset your password: #{reset_password_email_link}" }
send_email do |email|
# queue email delivery on the mailer after the transaction commits
db.after_commit { email.deliver_later }
end
# ==> Flash
<% unless json? || jwt? -%>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class <%= options[:name].camelize %>Mailer < ApplicationMailer
class RodauthMailer < ApplicationMailer
def verify_account(recipient, email_link)
@email_link = email_link

Expand Down
13 changes: 13 additions & 0 deletions test/generators/install_generator_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,17 @@ class InstallGeneratorTest < Rails::Generators::TestCase

assert_file "app/models/account.rb", /class Account < ApplicationRecord/
end

test "mailer" do
run_generator

assert_file "app/mailers/rodauth_mailer.rb", /class RodauthMailer < ApplicationMailer/

%w[
verify_account verify_login_change unlock_account reset_password
password_changed email_auth
].each do |template|
assert_file "app/views/rodauth_mailer/#{template}.text.erb"
end
end
end
34 changes: 0 additions & 34 deletions test/generators/mailer_generator_test.rb

This file was deleted.

0 comments on commit 7890515

Please sign in to comment.