I need to adapt the forgot password instructions to handle a subdomain. I have followed the instructions on the devise site to override the mailer, controller and add a subdomain helper etc. as listed:
controllers/password_controller.rb
class PasswordsController < Devise::PasswordsController
def create
@subdomain = request.subdomain
super
end
end
routes.rb
devise_for :users, controllers: { passwords: 'passwords' }
devise.rb
config.mailer = "UserMailer"
mailers/user_mailer.rb
class UserMailer < Devise::Mailer
helper :application # gives access to all helpers defined within `application_helper`.
def confirmation_instructions(record, opts={})
devise_mail(record, :confirmation_instructions, opts)
end
def reset_password_instructions(record, opts={})
devise_mail(record, :reset_password_instructions, opts)
end
def unlock_instructions(record, opts={})
devise_mail(record, :unlock_instructions, opts)
end
end
views/user_mailer/reset_password_instructions.html.erb
<p>Hello <%= @resource.email %>!</p>
<p>Someone has requested a link to change your password. You can do this through the link below.</p>
<p><%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token, :subdomain => @subdomain) %></p>
<p>If you didn't request this, please ignore this email.</p>
<p>Your password won't change until you access the link above and create a new one.</p>
helpers/subdomain_helper.rb
module SubdomainHelper
def with_subdomain(subdomain)
subdomain = (subdomain || "")
subdomain += "." unless subdomain.empty?
host = Rails.application.config.action_mailer.default_url_options[:host]
[subdomain, host].join
end
def url_for(options = nil)
if options.kind_of?(Hash) && options.has_key?(:subdomain)
options[:host] = with_subdomain(options.delete(:subdomain))
end
super
end
end
application.rb
config.to_prepare do
Devise::Mailer.class_eval do
helper :subdomain
end
end
Now, this code is all working but it just can't get the value of @subdomain in the mailer view. If I replace @subdomain with a hard-coded string then the correct url is passed in the email so I know the code is all correct.
How do I get the instance variable @subdomain defined in the controller into the mailer view?
The solutions above won't work with if you want to pass subdomain to "confirmation email" as well because it is handled entirely in model.
I have solved both scenarios (forgot password and confirmation email) by storing the subdomain (or whatever other context) with the request_store gem, and then setting up my own mailer to use this value.
The only thing needed to override in
User
class is thesend_devise_notification
method to include the intel stored in the request store.Of course, you have to configure devise to use your mailer in
config/initializers/devise.rb
.Here's an updated answer that I think solves your question nicely - https://github.com/plataformatec/devise/wiki/How-To:-Send-emails-from-subdomains
In my case my subdomain was stored in my Accounts table and here's what I did to allow me to use
@resource.subdomain
in my devise mailer viewsFor devise 3.1 the above monkey patching in user model can be like below. This in the case your subdomain is stored in a seperate model(say tenants) that has no relation to other models like accounts, users what ever it be..(find like current_tenant.subdomain)
I've found a way. I will think if I can find a better way without having to monkey patch stuff and having to chain it up the subdomain.
Basically, I override the controller doing this:
Also, I had to monkey patch this methods on my user model:
And finally, I had to monkey patch
devise_mail
methods, which lives inside Devise.Doing this, the
@subdomain
variable appeared on the mailer template. I'm not happy with this solution, but this is a starting point. I will think on any improvements on it.