Search code examples
ruby-on-railsrubypostgresqlbcrypt-ruby

Ruby on Rails hashed password using BCrypt not saving to postgres users table


I am trying to hash a password using bcrypt-ruby and save it to a postgres users table but I cannot get the hash to save properly. Can someone tell me what I am doing wrong? This is what I have tried:

User Model:

require 'bcrypt'

class User < ApplicationRecord
  include ActiveModel::SecurePassword
  include BCrypt

  has_secure_password

  attr_accessor :password
  attr_accessor :password_digest

  enum :user_type, { :registered => 1, :administrator => 2 }



  validates :email, presence: true

  validates_format_of :email,  with: URI::MailTo::EMAIL_REGEXP 
  validates :password_digest, presence: true
  validates :password_confirmation, presence: true

end

Rails Migration:

class User < ActiveRecord::Migration[7.0]
  create_table :users do |t|
    t.string :username,           null: false, default: ""
    t.string :email,              null: false, default: ""
    t.string :password_digest,    null: false, default: ""


    t.string :user_type,          default: 'registered'


    t.timestamps null: false
  end

  add_index :users, :username,             unique: true
  add_index :users, :email,                unique: true
  add_index :users, :user_type

end

Rails Console:

include BCrypt

@user = User.new
@user.username = "test123456"
@user.email="[email protected]"
@user.user_type = 1
@user.password = "test123456"
@user.password_digest = Password.create("test123456")
@user.password_confirmation = "test123456"
@user.save!

Generated SQL in Rails Console:

  TRANSACTION (0.2ms)  BEGIN
  User Create (0.4ms)  INSERT INTO "users" ("username", "email", "password_digest", "user_type", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"  [["username", "test123456"], ["email", "[email protected]"], ["password_digest", "[FILTERED]"], ["user_type", "1"], ["created_at", "2024-10-03 13:53:37.193227"], ["updated_at", "2024-10-03 13:53:37.193227"]]
  TRANSACTION (0.8ms)  COMMIT

Postgres:

enter image description here


Solution

  • You need to remove these two line from your User model:

    attr_accessor :password
    attr_accessor :password_digest
    

    Because those are overriding the getter and setter models that are created automatically by Ruby and Rails.

    And I suggest changing

    validates :password_confirmation, presence: true
    

    to

    validates :password_confirmation, presence: true, on: :create
    

    Because the password_confirmation is only set when the user sets or updates the password. When the user, for example, want to change their email, the password_confirmation would be blank, because it is not stored to the DB.