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
Related
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
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
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 :)
I want to specify a custom 'from' email when sending out devise emails.
So far I have created a customer mailer, and am overwriting part of the default methods, but I have no clue on how to pass in arguments, like current_user
Example:
class CustomDeviseMailer < Devise::Mailer
helper :application
include Devise::Controllers::UrlHelpers
default template_path: 'devise/mailer'
def confirmation_instructions(record, token, opts = {})
Rails.logger.debug 'Sending custom confirmation instructions...'
customer_responsible = current_user.company
info_email = customer_responsible.info_email
opts[:from] = info_email if info_email
super
rescue => e
Rails.logger.debug e.inspect
throw e
end
end
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