Authentication is a deal breaking feature in any applications nowadays. In Rails, Devise makes authentication a breeze; install a gem, run few commands and you have authentication working in your app.
Today, with the help of Devise we will look into a solution for a very common feature request in the app; throw validation error if user tries to change their password but add the same old password.
Skills required to follow the tutorial
Intermediate:
- Rails
You should have
- Existing Rails app with authentication already handled using Devise
Validation Implementation
Let's dive into the code now.
Add the following validation error to the model that is used for authentication:
class User < ApplicationRecord
# ============ Custom Validation ============
validate :new_and_old_password_must_be_different
private
def new_and_old_password_must_be_different
return if changed.exclude?('encrypted_password')
password_is_same = Devise::Encryptor.compare(User, encrypted_password_was, password)
errors.add(:password, I18n.t('validations.not_allowed.old_password')) if password_is_same
end
end
Please note that I am using "User" model for storing all users and authenticate them but table could be anything else like "Admin" as well.
We will understand what each line of code means in next section.
Code Explanation
-
changed.exclude?('encrypted_password')
ActiveModel stores changes that were made in the current transaction inside the variable "changed" and with this line of code we are returning early from the validation if user was updated but password wasn't updated.
-
Devise::Encryptor.compare(User, encrypted_password_was, password)
We are already using Devise for authentication so we are reaching out to the helper module "Encryptor" from Devise to compare new password with the old one. Here, current password will be in plain format and "Encryptor" will hash the password with relevant algorithm before comparing so we know if the password is same or different.
This line will return true if previous password is same as the new password or false if they are different.
-
errors.add(:password, I18n.t('validations.not_allowed.old_password'))
Lastly, we are adding validation errors to the User model if the password is same. And controller action will return the validation error to show it in frontend.
Conclusion
And with that we have successfully added a way for our app to throw validation errors when old password is used with the help of Devise. I hope you got to learn something new today.
Thank you for reading. Happy coding!
References
Image Credits
- Cover Image by alexander ehrenhöfer on Unsplash
Top comments (0)