I override devise's confirm! method to send a welcome message to my users:
class User < ActiveRecord::Base
devise :invitable, :database_authenticatable, :registerable, :recoverable,
:rememberable, :confirmable, :validatable, :encryptable
# ...
# Devise confirm! method overriden
def confirm!
UserMailer.welcome_alert(self).deliver
super
end
end
With devise_invitable when the user accept the invitation and set his password the confirm! method is never triggered, is it possible to force it? How does devise_invitable confirms the User?
Or maybe I can override the accept_invite (or whatever its called) method the same way?
I want that invited users remain unconfirmed, and then confirmed upon accepting the invitation.
Thanks, any help very appreciated!
Original Source
UPDATE
Looking through devise_invitable model I found the two methods who may be causing this misbehavior:
# Accept an invitation by clearing invitation token and confirming it if model
# is confirmable
def accept_invitation!
if self.invited? && self.valid?
self.invitation_token = nil
self.save
end
end
# Reset invitation token and send invitation again
def invite!
if new_record? || invited?
#skip_password = true
self.skip_confirmation! if self.new_record? && self.respond_to?(:skip_confirmation!)
generate_invitation_token if self.invitation_token.nil?
self.invitation_sent_at = Time.now.utc
if save(:validate => self.class.validate_on_invite)
self.invited_by.decrement_invitation_limit! if self.invited_by
!!deliver_invitation unless #skip_invitation
end
end
end
class User < ActiveRecord::Base
devise :invitable, :database_authenticatable, :registerable, :recoverable,
:rememberable, :confirmable, :validatable, :encryptable
# ...
# devise confirm! method overriden
def confirm!
welcome_message
super
end
# devise_invitable accept_invitation! method overriden
def accept_invitation!
self.confirm!
super
end
# devise_invitable invite! method overriden
def invite!
super
self.confirmed_at = nil
self.save
end
private
def welcome_message
UserMailer.welcome_message(self).deliver
end
end
I tried benoror's answer and at first it appeared to work - but when you a user accepts the invitation and fills in the form as invalid it will actually override the token invalidating the invitation.
Instead, a callback is available to do this:
class User < ActiveRecord::Base
devise :invitable, :database_authenticatable, :registerable, :recoverable,
:rememberable, :confirmable, :validatable, :encryptable
after_invitation_accepted :send_welcome_email
def send_welcome_email
end
end
Related
I'm using rails 5.2 and devise 4.4.3, I have confirmable working, however, I'm trying to have it so when the user confirms their account they get sent another email welcoming them to the website.
On sign up the confirmation email sends and confirmation can take place by clicking the link in the email but the welcome email that I want to be sent after this currently doesn't send.
The code I have is like so, I have generated a UserMailer and done the following
user.rb model
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
has_one_attached :avatar
def confirm!
welcome_email
super
end
protected
def welcome_email
UserMailer.welcome_email(self).deliver
end
end
views/user_mailer/welcome_email.html.erb
<h2>Welcome <%= #user.email %></h2>
mailers/user_mailer.rb
class UserMailer < ApplicationMailer
def welcome_email(user)
#user = user
mail(to: #user.email, subject: "Welcome! You are awesome!")
end
end
You can use the after_confirmation callback instead of trying to override confirm.
def after_confirmation
UserMailer.welcome_email(self).deliver
end
def after_confirmation
UserMailer.with(user: #user, password: #user.password).welcome_email.deliver_later
end
I have a devise model called members i am using devise confirmable. Upon confirm i want to send a welcome email to the User
class Member < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
# Methods
# Override devise confirm! message
def confirm!
welcome_email
super
end
# Private Methods
private
def welcome_email
MemberMailer.welcome_email(self).deliver
end
end
My MemberMailer resides in mailers/brands/member_mailer.rb
class Brands::MemberMailer < ApplicationMailer
# Send Welcome Email once Member confirms the account
def welcome_email(member)
#member = member
mail(to: #member.email, subject: "Welcome to Skreem! Now you Rock!")
end
end
But upon confirming through the mail Link the confirm! is not being overridden and I am not getting any error or email.
Add this to your Member model:
def after_confirmation
welcome_email
end
For more info check after_confirmation
#Pavan thanks for pointing this.
Your welcome_email should be:
def welcome_email
Brands::MemberMailer.welcome_email(self).deliver
end
I created a user model using devise. I was wondering how can I create views and methods that only work after I've signed in?
Here is my model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:rememberable, :validatable
end
controller:
class UserController < ApplicationController
def create
User.create(user_params)
end
private
def user_params
# required input for params
# permit - returns a version of the params hash with ony the permitted attributes
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end
You will be protecting controllers and it's actions.
before_action :authenticate_user!
user_signed_in?
current_user
user_session
read more!
https://github.com/plataformatec/devise
I'm new to rails and I tried to make simple authentication with anonymous user. I followed this tutorial and I have this error:
undefined method `find_or_initialize_by_token'
This is my AnonymousUser model:
class AnonymousUser < User
ACCESSIBLE_ATTRS = [:name, :email]
attr_accessible *ACCESSIBLE_ATTRS, :type, :token, as: :registrant
def register(params)
params = params.merge(type: 'User', token: nil)
self.update_attributes(params, as: :registrant)
end
end
This is my User model:
class User < ActiveRecord::Base
devise :database_authenticatable, :confirmable, :lockable, :recoverable,
:rememberable, :registerable, :trackable, :timeoutable, :validatable,
:token_authenticatable
attr_accessible :email, :password, :password_confirmation, :remember_me
end
And the last one important is my ApplicationController which has this error:
class ApplicationController < ActionController::Base
protect_from_forgery
def authenticate_user!(*args)
current_user.present? || super(*args)
end
def current_user
super || AnonymousUser.find_or_initialize_by_token(anonymous_user_token).tap do |user|
user.save(validate: false) if user.new_record?
end
end
private
def anonymous_user_token
session[:user_token] ||= SecureRandom.hex(8)
end
end
Someone told me that if AnonymousUser user inherits from User then AnonymousUser have method called find_or_initialize_by_token, but i don't know how to fix it.
Provided you have latest rails installed, try to refactor:
# in ApplicationController#current_user
AnonymousUser.find_or_initialize_by_token(anonymous_user_token).tap do |user|
user.save(validate: false) if user.new_record?
end
to something like this:
AnonymousUser.safely_find(anonymous_user_token)
and push the find_or_initialize_by_token and save(validate: false) into the model.
I wrote the blog post you referenced, but today, I would use
AnonymousUser.where(anonymous_user_token: anonymous_user_token).first_or_initialize
Dynamic finders have been deprecated AFAIK.
However, #Saurabh Jain is absolutely correct in his suggestion to refactor that block into a nice little push-button class method on the AnonymousUser.
Is there a way to create a after_confirmation :do_something ?
The goal is to send an e-mail after the user confirms using Devise :confirmable.
I'm using Devise 3.1.2, it has a placeholder method after_confirmation which is called after the confirmation finished successfully. We just need to override this method in User model.
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
# Override Devise::Confirmable#after_confirmation
def after_confirmation
# Do something...
end
end
See: Devise 3.5.9 Source Code: https://github.com/plataformatec/devise/blob/d293e00ef5f431129108c1cbebe942b32e6ba616/lib/devise/models/confirmable.rb
For new versions of devise 3.x :
See a different answer http://stackoverflow.com/a/20630036/2832282
For old versions of devise 2.x :
(Original answer)
but you should be able to put a before_save callback on the user (extra credit for using an observer) and check if confirmed_at was just set by devise. You can do something like:
send_the_email if self.confirmed_at_changed?
http://api.rubyonrails.org/classes/ActiveModel/Dirty.html for more details on checking the change on the field.
You can override the confirm! method:
def confirm!
super
do_something
end
Discussion about the topic is at https://github.com/plataformatec/devise/issues/812. They say that there are no callbacks like after_confirmation :do_something because that approach would require a lot of different callbacks.
Rails 4:
combining multiple answers above
def first_confirmation?
previous_changes[:confirmed_at] && previous_changes[:confirmed_at].first.nil?
end
def confirm!
super
if first_confirmation?
# do first confirmation stuff
end
end
according to the Devise 3.5.9 source code, you can simply define a method on the Devise Resource model, e.g.:
class User < ActiveRecord::Base
...
def after_confirmation
do_something
end
end
See: Devise 3.5.9 Source Code: https://github.com/plataformatec/devise/blob/d293e00ef5f431129108c1cbebe942b32e6ba616/lib/devise/models/confirmable.rb
I don't see that callback too, maybe you can try to override the confirmation method and call your callback there.
def send_confirmation_instructions(attributes={})
super(attributes)
your_method_here
end
You can override the confirm! method on your model
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
def confirm!
super
do_something
end
end
There is a discussion about the topic is https://github.com/plataformatec/devise/issues/812. I tried this way, and it worked great.
We're combining answers from #BernĂ¡t and #RyanJM:
def confirm!
super
if confirmed_at_changed? and confirmed_at_was.nil?
do_stuff
end
end
This seems a bit more performance aware and safe than the two answers separately.