This blog is part of our Rails 6 series. Rails 6.0 was recently released.

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

>> class User < ApplicationRecord >> has_secure_password >> end => [ ActiveModel :: Validations :: ConfirmationValidator ] >> user = User . create ( email: 'amit.choudhary@bigbinary.com' , password: 'amit.choudhary' ) BEGIN User Create ( 0.8 ms ) INSERT INTO "users" ( "email" , "password_digest" , "created_at" , "updated_at" ) VALUES ( $1 , $2 , $3 , $4 ) RETURNING "id" [[ "email" , "amit.choudhary@bigbinary.com" ], [ "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: "amit.choudhary@bigbinary.com", 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: "amit.choudhary@bigbinary.com", 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

Rails 6.0.0.beta2

>> class User < ApplicationRecord >> has_secure_password >> has_secure_password :transaction_password >> end => [ ActiveModel :: Validations :: ConfirmationValidator ] >> user = User . create ( email: 'amit.choudhary@bigbinary.com' , password: 'amit.choudhary' , transaction_password: 'amit.choudhary' ) BEGIN User Create ( 0.5 ms ) INSERT INTO "users" ( "email" , "password_digest" , "transaction_password_digest" , "created_at" , "updated_at" ) VALUES ( $1 , $2 , $3 , $4 , $5 ) RETURNING "id" [[ "email" , "amit.choudhary@bigbinary.com" ], [ "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: "amit.choudhary@bigbinary.com", 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: "amit.choudhary@bigbinary.com", 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: "amit.choudhary@bigbinary.com", 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.