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.
Rails 5.2
1>> class User < ApplicationRecord 2>> has_secure_password 3>> end 4 5=> [ActiveModel::Validations::ConfirmationValidator] 6 7>> user = User.create(email: '[email protected]', password: 'amit.choudhary') 8BEGIN 9User 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"]] 10COMMIT 11 12=> #<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"> 13 14>> user.authenticate('amit.choudhary') 15 16=> #<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"> 17 18>> class User < ApplicationRecord 19>> has_secure_password :transaction_password 20>> end 21 22=> NoMethodError: undefined method 'fetch' for :transaction_password:Symbol 23 from (irb):9:in '<class:User>' 24 from (irb):8
Rails 6.0.0.beta2
1>> class User < ApplicationRecord 2>> has_secure_password 3>> has_secure_password :transaction_password 4>> end 5 6=> [ActiveModel::Validations::ConfirmationValidator] 7 8>> user = User.create(email: '[email protected]', password: 'amit.choudhary', transaction_password: 'amit.choudhary') 9BEGIN 10User 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"]] 11COMMIT 12 13=> #<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"> 14 15>> user.authenticate('amit.choudhary') 16 17=> #<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"> 18 19>> user.authenticate_transaction_password('amit.choudhary') 20 21=> #<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.