Devise and localized own mail template - ruby-on-rails

I'm using devise gem and want to translate confirmation mail. I already got my own template and overridden mailer method:
class LocalizedDeviseMailer < Devise::Mailer
def confirmation_instructions(record, locale)
#locale = locale
super
end
end
So, in my template I can do something like that:
I18n.locale = #locale
And then:
t("it.really.works")
But I don't know how to pass my variable with locale to mailer method. What is the best way to do that? Any help would be appreciated.

Devise is offering the localisation of mail template "natively".
have a look at the devise source code
https://github.com/plataformatec/devise/blob/master/lib/devise/mailers/helpers.rb
In this file is explained how to localise the subject (to be added to your locales files)
# Setup a subject doing an I18n lookup. At first, it attemps to set a subject
# based on the current mapping:
#
# en:
# devise:
# mailer:
# confirmation_instructions:
# user_subject: '...'
#
This is then the body template that you need to localise as any other html.erb
https://github.com/plataformatec/devise/blob/master/app/views/devise/mailer/confirmation_instructions.html.erb
Depending if your new user will sign_up using http://yoursite/it/users/sign_up or http://yoursite/en/users/sign_up (as you would normally do in your routes for your localised application) the good localised subject and mail (in the former case in Italian, in the latter in English) will be sent.

I recommend to add a locale column to your User model and use your own mailer.
This way you have also more flexibility, if you plan to set your own stylesheets and from fields or add additional mails.
in config/initializer/devise.rb:
Devise.setup do |config|
...
config.mailer = "UserMailer"
...
end
in app/mailers/user_mailer.rb
class UserMailer < Devise::Mailer
default from: "noreply#yourdomain.com"
def confirmation_instructions(user)
#user = user
set_locale(#user)
mail to: #user.email
end
def reset_password_instructions(user)
#user = user
set_locale(#user)
mail to: #user.email
end
def unlock_instructions(user)
#user = user
set_locale(#user)
mail to: #user.email
end
private
def set_locale(user)
I18n.locale = user.locale || I18n.default_locale
end
end

One more way is to add the initializer:
require 'devise/mailer'
module Devise
class Mailer
module Localized
%w(
confirmation_instructions
reset_password_instructions
unlock_instructions
).each do |method|
define_method(method) do |resource, *args|
I18n.with_locale(resource.try(:locale)) do
super(resource, *args)
end
end
end
end
prepend Localized
end
end
For ruby <2.1 you can use concern with alias_method_chain.

I think the simplest way to do that is add it on record. So you can add a locale column in your User or juste add an attr_accessor :locale in your User model
So you just need define this locale in your record and use it with I18n.locale = record.locale

Related

Override Devise Invitable `invite!` method in order to add attachment to invitation email - Rails

I have devise_invitable gem and an invitations controller InvitationsController < Devise::InvitationsController. I invite my user with this method User.invite!(user, inviter) from the gem.
Now, I would like to add pdf attachment to this invitation but I am not able to override the mailer method in order to do stuff like this: attachments['terms.pdf'] = File.read('/path/terms.pdf').
My invitation email is working fine and I would like to keep it like that but with an attachment.
Here my routes.rb:
devise_for :users, controllers: { invitations: 'api/v1/users/invitations' }
What am I missing?
Thanks 🙏
DeviseInvitable has a usefull skip_invitation option.
With the following method you can easily use your own mailer and add attachment in it :
def invite_and_notify_user(email)
user = User.invite!({ email: email }) do |u|
u.skip_invitation = true
end
notify_by_email(user)
end
def notify_by_email(user)
MyUserMailer.invited_user_email(user).deliver
end
In MyUserMailer class:
def invited_user_email(user)
#user = user
attachments['terms.pdf'] = File.read('/path/terms.pdf')
mail(to: user.email, from: 'contact#mail.com', subject: "Your subject")
end
You can override the devise mailer like so...
class MyMailer < Devise::Mailer
helper :application # gives access to all helpers defined within `application_helper`.
include Devise::Controllers::UrlHelpers # Optional. eg. `confirmation_url`
default template_path: 'devise/mailer' # to make sure that your mailer uses the devise views
# If there is an object in your application that returns a contact email, you can use it as follows
# Note that Devise passes a Devise::Mailer object to your proc, hence the parameter throwaway (*).
default from: ->(*) { Class.instance.email_address }
end
You can then in your config/initializers/devise.rb, set config.mailer to "MyMailer". Note that this overrides the mailer used for all devise modules.
Then in that class add your attachment to invited_user_instructions...
def invited_user_instructions(*args)
attachments['terms.pdf'] = File.read('/path/terms/pdf')
super
end
This is devise's instructions https://github.com/heartcombo/devise/wiki/How-To:-Use-custom-mailer

How to call an ApplicationHelper method in Mailer with Ruby on Rails 6

I have a helper function to generate email for user as below
module ApplicationHelper
# Generate unique email for user based on their first and only cat id
def unique_email_for_user(user)
"category#{user.cats.first.id}#mywebsite.com"
end
end
I can call this unique_email_for_user function in my controllers, but not in my Mailer as below
class UserMailer < ApplicationMailer
# Call application_helpers
helper :application
# match the name to views/mailer/send_reminder.html.erb
def send_reminder(user)
#user = user
# Send email to user
mail(to: #user.email, reply_to: unique_email_for_user(#user), subject: "My email subject")
end
end
I get the error as below. I thought adding helper :application to my Mailer would make the necessary connections, No?
This worked
include ApplicationHelper
instead of
helper :application

Devise doesn't override email views

I have my scope views reset_password_instructions.html
and in my devise.rb
config.scoped_views = true
It works fine in development and sends the custom email. However, in production, when user receives email, device sent a default template.
How can I fix this in production?
when I use devise I this is what I do to send my own emails
class MyMailer < Devise::Mailer
helper :application # gives access to all helpers defined within `application_helper`.
include Devise::Controllers::UrlHelpers # Optional. eg. `confirmation_url`
default template_path: 'devise/mailer' # to make sure that your mailer uses the devise views
end
now, in your config/initializers/devise.rb, you can set config.mailer to "MyMailer".
You may now use your MyMailer in the same way as any other mailer. In case you want to override specific mails to add extra headers, you can do so by simply overriding the method and calling super at the end of your custom method, to trigger Devise's default behavior.
You can also override any of the basic headers (from, reply_to, etc) by manually setting the options hash:
def confirmation_instructions(record, token, opts={})
headers["Custom-header"] = "Bar"
opts[:from] = 'my_custom_from#example.com'
opts[:reply_to] = 'my_custom_from#example.com'
super
end
In order to get preview (if User is your devise model name):
# test/mailers/previews/my_mailer_preview.rb
# Preview all emails at http://localhost:3000/rails/mailers/my_mailer
class MyMailerPreview < ActionMailer::Preview
def confirmation_instructions
MyMailer.confirmation_instructions(User.first, "faketoken", {})
end
def reset_password_instructions
MyMailer.reset_password_instructions(User.first, "faketoken", {})
end
def unlock_instructions
MyMailer.unlock_instructions(User.first, "faketoken", {})
end
end
I hope that this was useful :)

Changing devise_invitable mailer subject

on default, the subject for invitation mail is
mailer:
invitation_instructions:
subject: 'Invitation instructions'
I'd like to change it to
subject: '%{invited_by} has invited you!'
but this requires to have invited_by variable accessible to the translate method for i18n.
How can I have this variable accessible/declared without changing default behavior too much?
Devise default mailer won't work for you, but it's quite easy to set up a custom mailer and define there your own subject_for helper:
# in config/initializers/devise.rb:
...
config.mailer = "CustomDeviseMailer"
...
# in app/mailers/custom_devise_mailer.rb:
class CustomDeviseMailer < Devise::Mailer
protected
def subject_for(key)
return super unless key.to_s == 'invitation_instructions'
I18n.t('devise.mailer.invitation_instructions.subject',
:invited_by => resource.invited_by.try(:full_name) || 'Someone')
end
end

How do I set a custom email subject in a custom Devise email?

I am using Devise in a Rails 3 application to create accounts. I have different types of users, so I want to send out custom password recovery emails based on the type of user.
I am able to send the custom email, I haven't found a way to set custom headers on that email. I am particularly interested in setting the subject of the email.
I have done the following:
Created a custom Devise mailer with a custom method inside. This method calls devise_mail with parameters. In this case, the custom mailer is called "reset_partner_instructions". I am able to call this mailer and successfully send an email from my User model.
Created a custom email view template which is successfully being called from devise_mail.
My custom mailer looks like this:
class AccountMailer < Devise::Mailer
helper :application # gives access to all helpers defined within application_helper.
def reset_partner_instructions(record, opts={})
devise_mail(record, :reset_partner_instructions, opts)
end
end
The problem is that the subject of the email is always "Reset partner instructions". I believe Devise is generating this title from the name of the mail template.
In this tutorial https://github.com/plataformatec/devise/wiki/How-To:-Use-custom-mailer, they call the following code:
def confirmation_instructions(record, opts={})
headers["Custom-header"] = "Bar"
super
end
Since I'm calling "devise_mail" directly, I'm not seeing how to pass the headers intoto the mailer. Is there a simple setting or method I can use to set the email subject?
See devise helper
class AccountMailer < Devise::Mailer
def confirmation_instructions(record, opts={})
headers = {
:subject => "Subject Here"
}
super
end
end
Or you can change it in devise.en.yml file in intilizer directory
And set your own subject
mailer:
confirmation_instructions:
subject: 'Confirmation instructions'
It is very old question, it may be helpful still for you are others,
for custom subject:
create a file config/locales/devise.en.yml
add the content like this as shown below, make sure you do the indentation properly with 2 spaces as you do in database.yml file.
en:
devise:
mailer:
confirmation_instructions:
subject: 'Verification subject here'
reset_password_instructions:
subject: 'Reset password subject here'
This is an old question but still comes up at the top of search and I was able to solve this by setting opts[:subject] instead of setting the header:
# https://github.com/plataformatec/devise/wiki/How-To:-Use-custom-mailer
class DeviseMailer < Devise::Mailer
helper :application
include Devise::Controllers::UrlHelpers
default template_path: 'devise/mailer'
def confirmation_instructions(record, token, opts={})
opts[:subject] = ...
opts[:from] = ...
opts[:reply_to] = ...
super
end
end
And in devise.rb:
config.mailer = 'DeviseMailer'
I realized I should just use ActionMailer for this task. Devise wasn't giving me extra functionality, and since I was trying to generate a custom mailer, i could do that outside of Devise.
There's no need to set up a custom mailer or override Devise's confirmation_instructions method.
Devise let's you pass in optional parameters to the confirmation_instructions method that will get merged with Devise's default options (the opts hash gets passed through to Devise's headers_for helper).
So you could use the following code to send confirmation instructions with a custom subject:
Devise::Mailer.confirmation_instructions(user, {subject: "Custom Subject"}).deliver

Resources