Devise - how to require password if changing password - ruby-on-rails

I have a Rails 3 app and I want to show 4 main fields:
1. current password
2. current password confirm
3. new password
4. new password confirm
as well as a bunch of other fields for the user, and I only want to require the user to enter their current password if they enter a new password.
However, I cannot find how to do this in Devise.
What are the attributes of Devise to let me do this?

if you add
devise :validatable
to your user model, Devise will automatically validate your model. The validation logic can be found at:
https://github.com/plataformatec/devise/blob/master/lib/devise/models/validatable.rb#L53
you could also overwrite this method in your controller by simply overwriding the Devise method like so:
def password_required?
prepared? || !password.nil? || !password_confirmation.nil?
end

Related

Update devise user password using a custom method

I am using Devise for authentication and trying to change the password of certain users to their date of birth using a method
def set_dob_password id
#user = User.find(id)
#user.update_attribute(password: #user.birth_date)
end
isn't working
. What is the best way of doing this ?
Of course it won't work! Devise stores encrypted passwords only in the DB. If you look at the users table you won't see a 'password' field but 'encrypted_password' column instead.
You first have to encrypt the password.
pw = BCrypt::Password.create(#user.birth_date)
#user.update_attribute(:encrypted_password, pw)
Make sure you have the 'bcrypt' gem first.
#user.update_attributes(password: params[:password], password_confirmation: params[:password_confirmation]). You need to update both password + password confirmation. So in your case replace parmas with user DoB.

Automatically set password for user - Devise

Following this tutorial, I setup a simple registration system with devise, where a user enters their email address, they are sent a confirmation email, they click on it, it takes them to a form where they have to enter their password and complete the registration.
How do I skip that password form so that once the user clicks on the confirmation link in their email, their account is created? How can I automatically set simple password for all users?
Create a method in your user model to use it instead of the create method. Let's call it create_with_password
def self.create_with_password(attr={})
generated_password = attr[:first_name] + "123"
self.create(attr.merge(password: generated_password, password_confirmation: generated_password))
end
Override devise's registration controller to use your new method which generates the two necessary fields for devise password and password_confirmation using the first_name attribute in your user model for example then 123 like in John123
In your controller after your parameters are sanitized. You should call User.create_with_password(user_params)

How to match a new string with the password already encrypted

I am working on a rails 3.2.13 project. I am using devise plugin (devise gem 3.2.2, 1.4.2) for authentication. Using this plugin, how can I validate the current_password field while changing the old password to a new one? Or else, please suggest how I can achieve this by encrypting the given string and matching it with the password already saved without using the devise plugin.
E.g.: One user has encrypted_password like below:
"$2a$10$VrawKYj6zp10XUxbixVzE.7d4QgYjQn9aiuzAuP7fp3PZOLMP5wbu"
while changing the password, if I enter a current_password, it should match the string above (encrypted_password == current_password). How can I validate this?
I believe you need to break your problem down into the following steps:
Determine if the old_password is actually the user's current password.
To do this, you can call:
User.find_by_id([SOME_ID]).valid_password?(old_password)
If this returns true, then you can move on to the next step to begin changing of the password. If it doesn't, then the old_password is incorrect, and you should not allow the changing of password.
The implementation of valid_password? can be found in the Devise gem's /lib/devise/models/database_authenticatable.rb file (at around Line 40). You could use this implementation to roll your own code for validating a password. But, Devise pretty much does it for you if you call valid_password?, so rolling your own seems unnecessary.
If old_password is valid, then verify that new_password matches confirm_new_password.
if (new_password == confirm_new_password)
.
.
.
end
If these match, then set the new password by doing the following:
u = User.find_by_id([SOME ID])
u.password = new_password
u.password_confirmation = confirm_new_password
u.save
You can verify that the password has been changed by:
u.valid_password?(new_password)
Update user with current_password validation:
#user.update_with_password(account_update_params)
# account_update_params - should have :current_password, :password, :password_confirmation
It is default behaviour in Devise::RegistrationsController. If you want update user without password, you should overwrite controller's action
class UsersController < Devise::RegistrationsController
def update_resource(resource, params)
# resource.update_with_password(params)
resource.update_attributes(params)
end
end
Do I understand you right what you want allow users login with encrypted and unencrypted (usual) password?
We have:
user.valid_password?('Password2').should
code on github
So we can overwrite it inside models/user.rb
def valid_password?(password)
encrypted_password == password || super(password)
end

Optional password during authentication with Devise

If I've got a rails application and I'd like to add authentication to with Devise, how would I allow users who have a null password in the database to sign in without one?
I'm interested in hearing answers along the lines of the lifecycle and what files I'd have to author to get it done.
Step 1: Allow the record to be saved.
Step 2: Sign in the record
To allow the record to be saved, you'll want to do validations yourself. I describe here how to do custom validations: http://jessewolgamott.com/blog/2011/12/08/the-one-where-devise-validations-are-customized/ .... In your case, you'll want to remove the password validations.
To sign in the record, you'll need to have a custom sign in path. You can override the devise sessions controller, but this could do the trick:
class SessionsController < ApplicationController
def create
user = User.find_by_email!(params[:session][:email])
sign_in user
redirect_to root_path
end
end
It turns out, Devise is built on Warden. This means that I only have to create my own custom Warden strategy:
https://github.com/hassox/warden/wiki/Strategies

Rails Devise: Set password reset token and redirect user

In my app for a certain use case I create a new user (programmatically set the password) and send them a confirmation email.
I would like them to be able to change their password immediately after confirming (without having to enter the system generated one which I don't want to send them)
In effect I would like
1) System creates a new user account with generated password.
2) System sends confirmation email.
3) User clicks confirmation and is redirected to enter in their password (effectively send them to a URL like below)
Change my password
Any help / pointers would be great.
A simple way to have just one step for users to confirm email address and set initial password using the link you proposed...
Send one email your app generates, including a reset_password_token, and consider user's possession of that token confirmation of the validity of that email address.
In system account generation code, assuming User model is set up with :recoverable and :database_authenticatable Devise modules...
acct = User.new
acct.password = User.reset_password_token #won't actually be used...
acct.reset_password_token = User.reset_password_token
acct.email = "user#usercompany.com" #assuming users will identify themselves with this field
#set other acct fields you may need
acct.save
Make the devise reset password view a little clearer for users when setting initial password.
views/devise/passwords/edit.html.erb
...
<%= "true" == params[:initial] ? "Set your password" : "Reset your password" %>
...
Generated Email
Hi <%= #user.name %>
An account has been generated for you.
Please visit www.oursite.com/users/password/edit?initial=true&reset_password_token=<%= #user.reset_password_token %> to set your password.
No need to include :confirmable Devise module in your User model, since accounts created by your app won't get accessed without the reset_password_token in the email.
Devise will handle the submit and clear the reset_password_token field.
See devise_gem_folder/lib/devise/models/recoverable.rb and database_authenticatable.rb for details on reset_password_token method and friends.
If you want to use Devise :confirmable module rather than this approach, see the Devise wiki page.
In Rails 4.1, the following modification of Anatortoise House's reply works:
user = User.new
user.password = SecureRandom.hex #some random unguessable string
raw_token, hashed_token = Devise.token_generator.generate(User, :reset_password_token)
user.reset_password_token = hashed_token
user.reset_password_sent_at = Time.now.utc
user.email = 'user#usercompany.com'
user.save!
# Use a mailer you've written, such as:
AccountMailer.set_password_notice(user, raw_token).deliver
The email view has this link:
www.oursite.com/users/password/edit?initial=true&reset_password_token=<%= #raw_token %>
Here is my snippet for mailer preview
class Devise::MailerPreview < ActionMailer::Preview
def reset_password_instructions
user = User.last
token = user.send(:set_reset_password_token)
Devise::Mailer.reset_password_instructions(user, token)
end
end
You can call
user.send(:set_reset_password_token)
It may not be stable, as it's a protected method but it can work for your case. Just cover it with a test.
(tested on Devise v. 3.4)

Resources