Letting Devise support multiple emails, allows you to:
:multi_email_authenticatable
, :multi_email_confirmable
and :multi_email_validatable
are provided by _devise-multiemail.
Add this line to your application's Gemfile
:
gem 'devise-multi_email'
Suppose you have already setup Devise, your User
model might look like this:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable
end
In order to let your User
support multiple emails, with _devise-multiemail what you need to do is just:
class User < ActiveRecord::Base
has_many :emails
# Replace :database_authenticatable, with :multi_email_authenticatable
devise :multi_email_authenticatable, :registerable
end
class Email < ActiveRecord::Base
belongs_to :user
end
Note that the :email
column should be moved from users
table to the emails
table, and a new primary
boolean column should be added to the emails
table (so that all the emails will be sent to the primary email, and user.email
will give you the primary email address). Your emails
table's migration should look like:
create_table :emails do |t|
t.integer :user_id
t.string :email
t.boolean :primary
end
You can choose whether or not users can login with an email address that is not the primary email address.
Devise::MultiEmail.configure do |config|
# Default is `false`
config.only_login_with_primary_email = true
end
The autosave
is automatically enabled on the emails
association by default. This is to ensure the primary
flag is persisted for all emails when the primary email is changed. When autosave
is not enabled on the association,
only new emails are saved when the parent (e.g. User
) record is saved. (Updates to already-persisted email records
are not saved.)
If you don't want autosave
to be enabled automatically, you can disable this feature. What this will do is
enable alternative behavior, which adds an after_save
callback to the parent record and calls email.save
on each email
record where the primary
value has changed.
Devise::MultiEmail.configure do |config|
# Default is `true`
config.autosave_emails = false
end
You may not want to use the association user.emails
or email.users
. You can customize the name of the associations used. Add your custom configurations to an initializer file such as config/initializers/devise-multi_email.rb
.
Note: model classes are inferred from the associations.
Devise::MultiEmail.configure do |config|
# Default is :user for Email model
config.parent_association_name = :team
# Default is :emails for parent (e.g. User) model
config.emails_association_name = :email_addresses
# Default is :primary_email_record
config.primary_email_method_name = :primary_email
end
# Example use of custom association names
team = Team.first
emails = team.email_addresses
email = EmailAddress.first
team = email.team
Sending separate confirmations to each email is supported. What you need to do is:
Declare devise :multi_email_confirmable
in your User
model:
class User < ActiveRecord::Base
has_many :emails
# You should not declare :confirmable and :multi_email_confirmable at the same time.
devise :multi_email_authenticatable, :registerable, :multi_email_confirmable
end
Add :confirmation_token
, :confirmed_at
and :confirmation_sent_at
to your emails
table:
create_table :emails do |t|
t.integer :user_id
t.string :email
t.boolean :primary, default: false
## Confirmable
t.string :unconfirmed_email
t.string :confirmation_token
t.datetime :confirmed_at
t.datetime :confirmation_sent_at
end
Then all the methods in Devise confirmable are available in your Email
model. You can do email#send_confirmation_instructions
for each of your email. And user#send_confirmation_instructions
will be delegated to the primary email.
Declare devise :multi_email_validatable
in the User
model, then all the user emails will be validated:
class User < ActiveRecord::Base
has_many :emails
# You should not declare :validatable and :multi_email_validatable at the same time.
devise :multi_email_authenticatable, :registerable, :multi_email_validatable
end
You can find the detailed configurations in the rails 5 example app.
The Devise README describes how to use ActiveJob to deliver emails in the background. Normally you would place the following code in your User
model, however when using _devise-multiemail you should place this in the Email
model.
# models/email.rb
def send_devise_notification(notification, *args)
devise_mailer.send(notification, self, *args).deliver_later
end
The gem works with all other Devise modules as expected -- you don't need to add the "multi_email" prefix.
class User < ActiveRecord::Base
devise :multi_email_authenticatable, :multi_email_confirmable, :multi_email_validatable, :lockable,
:recoverable, :registerable, :rememberable, :timeoutable, :trackable
end
You need to implement add/delete emails for a user as well as set/unset "primary" for each email.
You can do email.send_confirmation_instructions
for each email individually, but you need to handle that logic in some place (except for the primary email, which is handled by Devise by default). e.g. After a new email was added by a user, you might want to provide some buttons in the view to allow users to resend confirmation instructions for that email.
Migrating existing user records
After checking out the repo, run bundle install
to install dependencies.
Then, run bundle exec rake
to run the RSpec test suite.
Bug reports and pull requests are welcome on GitHub at https://github.com/allenwq/devise-multi_email. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
The gem is available as open source under the terms of the MIT License.