You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用BCrypt哈希Ruby on Rails密码无法保存至PostgreSQL用户表

问题:bcrypt-ruby哈希密码无法保存到PostgreSQL的users表

我尝试使用bcrypt-ruby对密码进行哈希处理并保存到PostgreSQL的users表中,但无法成功保存哈希值。以下是我的操作步骤:

用户模型(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迁移文件(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控制台操作(Rails Console)

include BCrypt

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

Rails控制台生成的SQL

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", "test123456@gmail.com"], ["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

PostgreSQL数据库情况

附截图显示密码哈希未正确保存


解决方案

你的代码存在几个核心问题,导致密码哈希无法正确持久化:

1. 错误覆盖了password_digest的存取方法

ActiveRecord会自动为数据库表字段生成对应的getter/setter方法,手动添加attr_accessor :password_digest会覆盖这些原生方法,导致哈希值无法写入数据库。

2. 冗余引入密码相关模块

has_secure_password已经内置了ActiveModel::SecurePassword的功能,并且自动集成了bcrypt,不需要额外require 'bcrypt'或include BCrypt。

3. 控制台操作冗余

设置has_secure_password后,只需提供password和password_confirmation,Rails会自动生成并保存password_digest,无需手动赋值。

修正后的用户模型

class User < ApplicationRecord
  has_secure_password

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

  validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
  validates :password, presence: true, confirmation: true
  validates :username, presence: true, uniqueness: true
end

修正后的控制台操作

@user = User.new(
  username: "test123456",
  email: "test123456@gmail.com",
  user_type: :registered,
  password: "test123456",
  password_confirmation: "test123456"
)
@user.save!

额外迁移文件修正

原迁移中user_type定义为字符串类型,但enum使用整数映射,建议改为整数类型避免类型不匹配,同时修正迁移文件名(需遵循[action]_table_name规范):

class CreateUsers < ActiveRecord::Migration[7.0]
  def change
    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.integer :user_type, default: 1

      t.timestamps null: false
    end

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

执行修正后的代码后,通过User.last.password_digest可以验证是否生成了以$2a$开头的bcrypt哈希值。

内容的提问来源于stack exchange,提问作者user1645914

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 18:34:57