Devise custom after confirmation action - ruby-on-rails

Switching from my own auth solution to Devise, I'm trying to integrate with my mail service, Convertkit.
I'm trying to make devise call my method after confirming a user but I'm not sure how to call the resource.
I tried both these solutions:
https://stackoverflow.com/a/25336930/6848493
https://stackoverflow.com/a/16423638/6848493
Here's my User model:
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable, :lockable, :lastseenable, :timeoutable
validates :terms_and_privacy_policy,
acceptance: { accept: true }, on: :create, allow_nil: false
validates :first_name, presence: true
validates :last_name, presence: true
def confirm!
super
subscribe self
self.send_convertkit_failure unless #ck_response_code == 200
end
# Send email to admin in case of ConvertKit API failure
def send_convertkit_failure
UserMailer.convertkit_failure(self).deliver_now
end
Here's my user helper:
module UsersHelper
def subscribe(user)
response = HTTParty.post("https://api.convertkit.com/v3/forms/form/subscribe",
query: {email: user.email, first_name: user.name, course_opted: true, api_secret: 'my secret' })
#ck_response_code = response.code
end
end
There is no error message, it confirms the user okay but it doesn't subscribe them to convertkit. I've tried the same code but with resource
as the object but that throws an error.
As for the second method (writing to after_confirmation), it errors saying the user has already been confirmed.
Would really appreciate your input, thanks in advance.

Finally got this to work, in my User model:
# Override Devise::Confirmable#after_confirmation
def after_confirmation
subscribe self
self.send_convertkit_failure unless #ck_response_code == 200
end

Related

Devise: Authenticate with Just Username Only Instead of Email

everyone!
So I'm building an application that only needs a username for authentication and not an email.
In my config/initializers/devise.rb, I changed the :email to :username resulting to this
config.authentication_keys = [:username]
config.case_insensitive_keys = [:username]
config.strip_whitespace_keys = [:username]
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :stores
has_many :customers, through: :stores
has_many :visits, through: :stores
has_many :mall_managers
validates :name, presence: true
validates :username, presence: true, uniqueness: true
end
I also edited the views accordingly.
When I try to sign up I get an error:
NoMethodError in Devise::RegistrationsController#create
undefined method `email' for #<User:0x000000011bd61b38>
i guess your user table does not contain email column, but the module validatable of gem devise will validates_presence_of the email, so that error will be raised.
however module validatable allow you ignore email validation by override email_required? method
class User < ApplicationRecord
# ...
def email_required?
false
end
def will_save_change_to_email?
false
end
def email_changed?
false
end
end
update i found more 2 methods need to override (as above), and who know what else (in future versions) ? so i recommend you add email database field (if the root cause i suspect (miss email) correct).

Rails devise doesn't redirect to root path

My user model looks like this in which type is column in user table and std is used just to get additional data at the time of user sign_up.Now when user(type: Student) login, devise again rendered the login page with message log in successful doesn't render the root_path and in log it is showing rollback transaction but when i refreshed the page then it render to root_path. This problem is only happening for type:Student and when i remove validates_presence_of :std line everything is running perfectly.
Now the question is why this is happening or how it can be done
?
class User < ApplicationRecord
attr_accessor :std
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates_presence_of :type
validates_presence_of :std , allow_blank: false , if: -> { type == 'Student' },
message: 'Student must add grade to continue'
end
Devise::RegistrationsController.rb
class RegistrationsController < Devise::RegistrationsController
def create
super
if params[:user][:type] == 'Student' and user_signed_in?
current_user.grade = Grade.new({cls: params[:user][:std].to_i})
current_user.save
end
end
private
def sign_up_params
params.require(:user).permit(:email, :password, :password_confirmation, :type, :std)
end
end
Solved.. I think it is also validating user(type:Student)at the time of login so i just added
validates_presence_of :std , allow_blank: false , if: -> { type == 'Student' and new_record? },
message: 'Student must add grade to continue'
Now it is only validating at the time of signup only.

Error Handling - Email LDAP - Rails

I'm beginner in Ruby on Rails and I need help
In my project, I need to catch on LDAP the e-mail of user.
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :ldap_authenticatable,:rememberable, :trackable
#validates :username, presence: true, uniqueness: true
validates :email, presence: true
validates_uniqueness_of :email
before_validation :get_ldap_email
before_save :get_ldap_email
def get_ldap_email
self.email = Devise::LDAP::Adapter.get_ldap_param(self.username,"mail").first
end
But If in LDAP doesn't have an e-mail, shows an RailsĀ“ error message and I want to redirect to a page with a message made by me.
So, in SessionController i want make an "if", but i don't have success to call the method.
class Users::SessionsController < Devise::SessionsController
require_relative '../../models/User.rb'
def create
super
if get_ldap_email == nil
# redirect to /errorlogin
end
end
And here show message
undefined local variable or method `get_ldap_email' for #
Users::SessionsController:0x67342e0>
Also I modificed the User for this...
def get_ldap_email
ldapEmail = Devise::LDAP::Adapter.get_ldap_param(self.username,"mail")
if ldapEmail == nil
else
self.email = ldapEmail.first
end
end
But now show this message
Validation failed: Email can't be blank
I don't what I need to do...
The issue is that you're calling super before your get_ldap_email, so the validation in Devise's SessionController is checking for a valid email. This should work:
def create
if get_ldap_email == nil
# redirect to /errorlogin
end
super
end

RSpec not doing reload or not saving object

I'm facing a problem with rspec.
This is my test code:
describe "email address with mixed case" do
let(:mixed_case_email) { "Foo#ExAMPle.CoM" }
it "should be saved as all lower-case" do
#user2 = FactoryGirl.create(:user, email: 'aaaa#aaa.com')
#user2.email = mixed_case_email
p #user2.email
p #user2.save!
p #user2.email
p #user2.reload.email
expect(#user2.reload.email).to eq mixed_case_email.downcase
end
end
My terminal outputs:
"Foo#ExAMPle.CoM"
true
"aaaa#aaa.com"
"aaaa#aaa.com"
My user model:
#encoding: UTF-8
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable,
:validatable, :confirmable, :lockable,
:timeoutable, :omniauthable
before_validation { self.email.downcase! if self.email }
validates :email, presence: true, length: {:maximum => 60}
end
Looks like reload or save are not working. Don't know what I can do. Have this same test in other projects but without devise. Can it be the reason of this problem?
It is devise :)
Devise does not allow you to change email without confirmation. When you set another email devise saves it in unconfirmed_email, generates confirmation_token and sends a email to confirm it. So you have a conflict with gem devise functionality.
Not sure but I think you can check that unconfirmed_email is downcased after saving

devise invitable do not validate model

First, excuse my poor english, I'm french... it's tricky to explain my problem !
I have a model User model in a Rails application:
class User < ActiveRecord::Base
attr_accessible :email, :gender, :lastname, :firstname
end
And a BackUser model that inherit from User:
class BackUser < User
# Class for Backoffice User
devise :database_authenticatable,
:rememberable,
:trackable,
:lockable,
:invitable,
:confirmable,
:validatable,
:validate_on_invite => true
attr_accessible :password, :password_confirmation, :remember_me, :active, :role
validates :role, presence: true,
inclusion: ["admin", "normal"]
validates :gender, presence: true
validates :firstname, presence: true
validates :lastname, presence: true
def admin?
self.role == 'admin'
end
end
This second class should validate the record before invite!
BUT, when I use the console to do the following:
u = BackUser.new
u.invite!
"u" is saved in database and an invitation is send to a blank email...
Do you know what I have to do?
Thans a lot!
I'm sure you've found a solution or workaround to your problem by now, but for any future SO users who encounter the same problem I found a pretty simple fix.
Devise Invitable's model configuration docs don't fully explain how to implement :validate_on_invite, but you have to set the configuration option to true - :validate_on_invite => true.
Here's what my devise method looks like in my User model for this to work correctly.
models/user.rb
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :invitable, :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :validate_on_invite => true
Now when I attempt to submit an invitation it is fully validating the record with what the validations I've set up in my User model before allowing the invitation to be sent and the user record to be created. Looking at the docs, I'm guessing you can also enable this setting in the devise initializer, but I haven't tried going that route.
*Second possible option to enable validation if needed
config/initializers/devise.rb
config.validate_on_invite = true
I've never been able to get the validation to work correctly for devise invitable. You can't use RobHeaton's suggestion either because you will receive a validation error on the password. I use this little hack to get validation to work:
def create
#user = User.new(user_params)
#user.valid?
#user.errors.messages.except!(:password) #remove password from errors
if (#user.errors.any?)
render 'new'
else
#user.invite!(current_user)
redirect_to user_path(#user)
end
end
It doesn't solve the mystery of why your behaviour is occurring, but:
if u.save
u.invite!
end
will give the end result you are after.

Resources