-
Notifications
You must be signed in to change notification settings - Fork 553
Customizing for different Invite use cases (emails etc.)
Sometimes you want to be able to send different invites for a variety of different reasons. Eg. Inviting a VIP user vs Inviting a regular user. Here is an example of doing it for a "friend" and for a "guest"
in your devise model, put
attr_writer :invitation_instructions
def deliver_invitation
if @invitation_instructions.present?
::Devise.mailer.send(@invitation_instructions, self).deliver
else
super
end
end
def self.invite_guest!(attributes={}, invited_by=nil)
self.invite!(attributes, invited_by) do |invitable|
invitable.invitation_instructions = :guest_invitation_instructions
end
end
def self.invite_friend!(attributes={}, invited_by=nil)
self.invite!(attributes, invited_by) do |invitable|
invitable.invitation_instructions = :friend_invitation_instructions
end
end
From here if you run User.invite_guest!(:email => '[email protected]')
you should get an error that says that Devise::Mailer has no method such as guest_invitation_instructions.
The way to fix this is to create your own mailer class that inherits from Devise::Mailer, and create those methods yourself. EG.
class InviteMailer < Devise::Mailer
def guest_invitation_instructions(record, opts={})
devise_mail(record, :guest_invitation_instructions, opts)
end
def friend_invitation_instructions(record, opts={})
devise_mail(record, :friend_invitation_instructions, opts)
end
end
in your devise.rb add the line
config.mailer = "InviteMailer"
to make invite mailer your default class to send emails (wont override your other emails, which will still be sent by devise mailer)
Lastly, create your views in views/invite_mailer/guest_invitation_instructions and you should be all set!
NOTE: When you create custom mailer (for example "InviteMailer") old devise mailer views should be moved to new mailer directory (just copy files from /app/views/devise/mailer/ to /app/views/invite_mailer/).
Sometimes you might want to add a dynamic email header instead of pulling something statically from config/locals
. For example, a personalized custom subject header. Here's an easy way to achieve this in devise older than 2.2.0, for >= 2.2.0 you must overwrite mailer and customize it:
class User < ActiveRecord::Base
#... regular implementation ...
# This method is called interally during the Devise invitation process. We are
# using it to allow for a custom email subject. These options get merged into the
# internal devise_invitable options. Tread Carefully.
#
def headers_for(action)
return {} unless invited_by && action == :invitation_instructions
{ subject: "#{invited_by.full_name} has given you access to their account" }
end
end
Sometimes you may want to allow users to customize the message being sent, e.g. add a personal greeting to the standard message.
To accomplish this you can use your own mailer instead of having devise email things for you.
class User < ActiveRecord::Base
attr_reader :raw_invitation_token
end
class InvitationsController < Devise::InvitationsController
def create
@from = params[:from]
@subject = params[:invite_subject]
@content = params[:invite_content]
@user = User.invite!(params[:user], current_user) do |u|
u.skip_invitation = true
end
NotificationMailer.invite_message(@user, @from, @subject, @content).deliver
@user.invitation_sent_at = Time.now.utc # mark invitation as delivered
if @user.errors.empty?
flash[:notice] = "successfully sent invite to #{@user.email}"
respond_with @user, :location => root_path
else
render :new
end
end
end
class NotificationMailer < ActionMailer::Base
def invite_message(user, from, subject, content)
@user = user
@token = user.raw_invitation_token
invitation_link = accept_user_invitation_url(:invitation_token => @token)
mail(:from => from, :bcc => from, :to => @user.email, :subject => subject) do |format|
content = content.gsub '{{first_name}}', user.first_name
content = content.gsub '{{last_name}}', user.first_name
content = content.gsub '{{full_name}}', user.full_name
content = content.gsub('{{invitation_link}}', invitation_link)
format.text do
render :text => content
end
end
end
end
The raw_invitation_token
only exists in newer versions of devise_invitable (compatible with devise >= 3.1).
Note that you must send the email with the user object instance that generated the token, as user.raw_invitation_token
is available only to the instance and is not persisted in the database.
We are essentially skipping the devise invitation email process all together and using our own mailer. We take the content as a parameter and send it as the body of the email. We even substitute placeholders with their actual values.
This solution will give you a lot of flexibility to do whatever you want with emails. You can even add a tracking pixel to it if you would like.