I am using custom mailer by overriding the devise mailer. It is working fine. But I need to pass some data to the mailer template so that when the confirmation email send to the user it contains some dynamic content. I have tried it using sessions,#resource and current_user method but both are not working. Is there any way to do that?
Custom mailer
class CustomMailer < 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 you mailer uses the devise views
def confirmation_instructions(record, token, opts={})
opts[:subject] = "Email Confirmation"
opts[:from] = 'no-reply#abc.com'
#data = opts[:custom_field]
super
end
end
in the controller
CustomMailer.confirmation_instructions(token, {custom_field: "abc"})
This is the code in template
We are happy to invite you as user of the <b> <%= #data %> </b>
Thanks.
First, read about Devise custom mailer to familiarize yourself with the process.
Briefly this is how you'd go about doing it:
in config/initializers/devise.rb:
config.mailer = "DeviseMailer"
Now you can just use DeviseMailer like you'd do for any other mailer in your project:
class DeviseMailer < 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
...
def invite(sender, recipient)
#sender = sender
#recipient = recipient
mail( :to => recipient.email,
:subject => "Invite by #{sender.name}"
)
end
...
end
You can now call the invite in your project and pass whatever variable you want to be able to access in your template.
i.e:
Calling the invite method:
DeviseMailer.invite(current_user, newContact).deliver
So in your view you can then just call the variable:
invite.html.erb
<p>Hello <%= #recipient.email %></p>
<% if #sender.email? %>
<p> some additional welcome text here from <%= #sender.email %> </p>
<% end %>
EDIT
To answer your specific question here is what you want to override:
def confirmation_instructions(record, token, opts={})
headers["Custom-header"] = "Bar"
opts[:from] = 'my_custom_from#domain.com'
opts[:reply_to] = 'my_custom_from#domain.com'
super
end
Then call it anywhere you want:
DeviseMailer.confirmation_instructions(User.first, "faketoken", {})
Related
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 use Devise for authentication in my Rails app.
In my registrations_controller I have a variable like this:
class RegistrationsController < Devise::RegistrationsController
def create
foo = "bar"
super
end
end
In my customized mailer I then try to access the foo variable. The opts argument seems to be the one to look at:
class CustomMailer < Devise::Mailer
helper :application
include Devise::Controllers::UrlHelpers
def confirmation_instructions(record, token, opts={})
Rails.logger.error opts[:foo].inspect
super
end
end
But how do I pass on the foo variable on, without overwriting a lot of methods?
First, read about Devise custom mailer to familiarize yourself with the process.
Briefly this is how you'd go about doing it:
in config/initializers/devise.rb:
config.mailer = "DeviseMailer"
Now you can just use DeviseMailer like you'd do for any other mailer in your project:
class DeviseMailer < 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
...
def confirmation_instructions(record, token, opts={})
headers["Custom-header"] = "Bar"
opts[:from] = 'my_custom_from#domain.com'
opts[:reply_to] = 'my_custom_from#domain.com'
super
end
...
end
You can now call the confirmation_instructions in your project and pass whatever variable you want to be able to access in your template.
i.e:
Calling the confirmation_instructions method:
DeviseMailer.confirmation_instructions(User.first, "faketoken", {})
confirmation_instructions.html.erb
<p> And then override the template according to you. <p>
Hope this will help you :)
I am receiving the error
undefined method `url' for nil:NilClass
when I am previewing my Devise mailers only. I am trying to add an inline image within my email.
# app/mailers/user_mailer.rb
class UserMailer < Devise::Mailer
include Devise::Controllers::UrlHelpers
helper :application
before_action :add_inline_attachment!
def reset_password_instructions(record, token, opts={})
super
end
#...
private
def add_inline_attachment!
attachments.inline['logo.jpg'] = File.read('app/assets/images/logo.jpg')
end
end
In my mailer view:
# app/views/user/mailer/reset_password_instructions.html.erb
<%= image_tag attachments['logo.jpg'].url %>
While setting up Devise I added the following configurations in order to have scoped views
# config/initializers/devise.rb
config.mailer = 'UserMailer'
config.scoped_views = true
The major part of my hair pulling is that this works with every mailer views including devise_invitable. It's the core Devise views password_change, reset_password_instructions, and email_change.
Things I have tried and failed:
# app/views/user/mailer/reset_password_instructions.html.erb
<%= image_tag attachments['logo.jpg'].try(:url) %>
That returns nil is not a valid asset source
I've also tried adding the attachment directly inside:
# app/mailers/user_mailer.rb
class UserMailer < Devise::Mailer
include Devise::Controllers::UrlHelpers
helper :application
#...
def reset_password_instructions(record, token, opts={})
attachments.inline['logo.jpg'] = File.read('app/assets/images/logo.jpg')
super
end
#...
end
Also, adding the root for the image:
# Both
attachments.inline['logo.jpg'] = File.read("#{Rails.root}/app/assets/images/logo.jpg")
# And
attachments.inline['logo.jpg'] = File.read(Rails.root.join("app/assets/images/logo.jpg"))
I can use Devise helper methods in regular views but don't know how to use it within my Mailer. I need to determine if user is signed in to construct proper email message.
class UserMailer < ActionMailer::Base
def receipt
end
end
receipt.text.erb
<% if user_signed_in? %> #Error: undefined method `user_signed_in?' for #<#<Class:0x35695fc>
Secret link
<% end %>
Actually, you can't and most of all, you shouldn't use this kind of Devise helper on your mailer.
Why ? Well, if you search Devise's code base for the user_signed_in? helper, you will find it in Devise::Controllers::Helpers module, as you can see here. This means that it is supposed to be used in a controller context, as it uses method such as request and warden that is only available on controllers.
If you must make any decision in your mail view based on whether a user is signed in or not, I would recommend you to pass this information from your controller to your mailer:
Your controller:
class UserController < ApplicationController
def your_action
UserMailer.receipt(user_signed_in?).deliver
#....
end
end
Your mailer:
class UserMailer < ActionMailer::Base
def receipt(signed_in)
#signed_in = singed_in
#....
end
end
Your mailer view:
<% if #signed_in %>
Secret link
<% end %>
I hope it helps !
You can pass it over from helper. Something like this
class UserMailer < ActionMailer::Base
def receipt
#is_signed = user_signed_in?
end
end
and
<% if #is_signed %>
Secret link
<% end %>
Given that request object is not working in ActionMailer, is there a way to detect current URL and set from option for custom devise mailer controller?
So this is what I have so far in application_controller.rb:
before_filter :images, :hide_sidebar, :global_vars, :set_mailer_host
before_action :sidebar_menu
def set_mailer_host
ActionMailer::Base.default_url_options[:host] = request.host_with_port
#host = request.env['HTTP_HOST'] unless request.env['HTTP_HOST'].include? 'localhost'
end
Devise Mailer custom class:
class DeviseMailer < Devise::Mailer
helper :application # gives access to all helpers defined within `application_helper`.
include Devise::Controllers::UrlHelpers # Optional. eg. `confirmation_url`
def confirmation_instructions(record, token, opts={})
if record.events.present?
name = record.events.last.name
#event = name
else
name = "#{record.first_name},"
end
opts[:from] = "noreply##{#host}" if #host
opts[:subject] ="#{name} Registration - Confirmation Required"
super
end
end
Also in Devise.rb I've set below:
config.mailer = 'DeviseMailer'
I don't know why I'm still getting default domain instead of the current URL.
Since I have multiple urls pointing to the same application, is there a way to detect this and configure for Devise Mailers?
Why won't you pass the host as argument to your mailer?
def confirmation_instructions(record, token, opts={}, host)
...
end
DeviseMailer.confirmation_instructions(..., #host).deliver