April 23, 2019
This blog is part of our Rails 6 series.
has_secure_password
is used to encrypt and authenticate passwords using
BCrypt . It assumes the model has a
column named password_digest
.
Before Rails 6,
has_secure_password
did not accept any attribute as a parameter. So, if we needed
BCrypt encryption on a different
column other than password_digest
, we would have to manually encrypt the value
before storing it.
Rails 6 makes it easy and allows custom attributes as a parameter to
has_secure_password
. has_secure_password
still defaults to password
so it
works with previous versions of Rails. has_secure_password
still needs the
column named column_name_digest
defined on the model.
has_secure_password
also adds the authenticate_column_name
method to
authenticate the custom column.
Let's check out how it works.
>> class User < ApplicationRecord
>> has_secure_password
>> end
=> [ActiveModel::Validations::ConfirmationValidator]
>> user = User.create(email: '[email protected]', password: 'amit.choudhary')
BEGIN
User Create (0.8ms) INSERT INTO "users" ("email", "password_digest", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["email", "[email protected]"], ["password_digest", "$2a$10$g6ZJNgakn4I1w/qjAx3vM.I76QSNjFCHtTtT9ovko/9Th50SEmIBO"], ["created_at", "2019-03-17 23:30:13.754379"], ["updated_at", "2019-03-17 23:30:13.754379"]]
COMMIT
=> #<User id: 1, email: "[email protected]", password_digest: "$2a$10$g6ZJNgakn4I1w/qjAx3vM.I76QSNjFCHtTtT9ovko/9...", created_at: "2019-03-17 23:30:13", updated_at: "2019-03-17 23:30:13">
>> user.authenticate('amit.choudhary')
=> #<User id: 1, email: "[email protected]", password_digest: "$2a$10$g6ZJNgakn4I1w/qjAx3vM.I76QSNjFCHtTtT9ovko/9...", created_at: "2019-03-17 23:30:13", updated_at: "2019-03-17 23:30:13">
>> class User < ApplicationRecord
>> has_secure_password :transaction_password
>> end
=> NoMethodError: undefined method 'fetch' for :transaction_password:Symbol
from (irb):9:in '<class:User>'
from (irb):8
>> class User < ApplicationRecord
>> has_secure_password
>> has_secure_password :transaction_password
>> end
=> [ActiveModel::Validations::ConfirmationValidator]
>> user = User.create(email: '[email protected]', password: 'amit.choudhary', transaction_password: 'amit.choudhary')
BEGIN
User Create (0.5ms) INSERT INTO "users" ("email", "password_digest", "transaction_password_digest", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["email", "[email protected]"], ["password_digest", "$2a$10$nUiO7E2XrIJx/sSdpG0JAOL00uFvPRH7kXHLk5f/6qA1zLPHIrpPy"], ["transaction_password_digest", "$2a$10$l6cTpHwV9xOEn2.OumI29OnualGpvr1CgrNrbuMuHyGTltko8eBG2"], ["created_at", "2019-03-17 23:42:28.723431"], ["updated_at", "2019-03-17 23:42:28.723431"]]
COMMIT
=> #<User id: 5, email: "[email protected]", password_digest: [FILTERED], transaction_password_digest: [FILTERED], created_at: "2019-03-17 23:42:28", updated_at: "2019-03-17 23:42:28">
>> user.authenticate('amit.choudhary')
=> #<User id: 5, email: "[email protected]", password_digest: [FILTERED], transaction_password_digest: [FILTERED], created_at: "2019-03-17 23:42:28", updated_at: "2019-03-17 23:42:28">
>> user.authenticate_transaction_password('amit.choudhary')
=> #<User id: 5, email: "[email protected]", password_digest: [FILTERED], transaction_password_digest: [FILTERED], created_at: "2019-03-17 23:42:28", updated_at: "2019-03-17 23:42:28">
Here is the relevant pull request.
If this blog was helpful, check out our full blog archive.