How to update password attribute with has_secure_password? - ruby-on-rails

I used has_secure_password for the User model. Now I am trying to use AJAX to update some of the user's attributes, including password. However, it looks like with has_secure_password, the password attribute no longer exists, replaced by password_digest. So when I am trying to do
user[:password] = "The password passed by AJAX"
user.save!
I got:
ActiveModel::MissingAttributeError (can't write unknown attribute
password)
The question is: What is the right way to update a user's password in this situation? Do I need to manually compute the hash and update the password_digest?
EDIT:
I am using Rails 4.2.1

Normally you just use:
user = User.find 1
user.password = 'Test123456789'
user.save
But, it sounds like you have not added a password_digest column to the users table or have not run the migrations.

Related

How to avoid password validation, if it is generated and consists in params

I have a user model with generate_password action.
When i create a new user, the password is generated automatically and inserted into params like:
"user_params"=>
{"name"=>"name",
"surname"=>"secname",
"password"=>"j6WW9kj6"}
, so user don't need to feel a password field. And as I have a password present validation, rails throw a validation error when I attempt to create new user.
With my understanding, I can say that you are trying to generate a password when the user is created for the first time.
I think for this problem you can use before_create in User model.
before_create :generate_password
The answer is pretty simple. I just should run password_generate method in users_controller, and ActiveRecord does all for me:
#user = User.new user_params
#user.password = #user.generate_password
Thanks.

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.

How to insert an already encrypted password on devise model?

I am a newbie in rails. I would like to ask if it's possible to insert an encrypted password(encrypted using devise default encryption) to devise model?
e.g:
User.csv
id,name,encrypted_password
1,dude,$2a$10$0.xEu5LvDbnmGVIqgIab8ej5o2b3eKa8KLevsg5bxIX0SHSOl5gye
I want to read this csv file and then insert the data to User model.
But I realized that you can't insert the already encrypted password normally on encrypted_password of User model. I'm thinking to decrypt the password but they say that it is bad for the system's security.
Update: It can now insert an encrypted password but the inserted password is different to the one on the csv since the devise automatically encrypts the password before inserting it to the database. Is there a way for devise model to detect if the password is already encrypted before inserting it to the database?
yes, you can set the encrypted_password value directly:
u = User.find(1)
u.update_attribute(:encrypted_password, "$2a$10$0.xEu5LvDbnmGVIqgIab8ej5o2b3eKa8KLevsg5bxIX0SHSOl5gye")
But you should make sure that you're not setting 'password', if you do this won't work as it'll encrypt it again, so
u = User.new
u.password = 'foo'
u.password_confirmation = 'foo'
u.encrypted_password = "$2a$10$0.xEu5LvDbnmGVIqgIab8ej5o2b3eKa8KLevsg5bxIX0SHSOl5gye" # this line will be ignored
u.save
u = User.new
u.encrypted_password = "$2a$10$0.xEu5LvDbnmGVIqgIab8ej5o2b3eKa8KLevsg5bxIX0SHSOl5gye" # this line will now work
u.save

Form_for editing resource without all attributes

I have a form_for established to edit a resource (here it is a user). In the model, it is specified that some attributes cannot be blank (e.g. password). I have a second form to edit this user as an admin. This form does not require the user password but can be filled to change this user's password. The problem is that the validation fails cause no password is specified (Validation fail: Password cannot be blank).
I'd like to know if there is a way to edit the resource this way, without deleting the password field from parameters when it's blank.
#user.update!(user_params)
You can do something like a param deletetion. In your update method before the save do something like.
if params["user"].has_key? "password"
if params["user"]["password"].empty? and user_is_admin?
params["user"].delete("password")
end
end
Replace user_is_admin? with your own admin checking method.

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

Resources