Rails 7集成Devise注册时encrypted_password未保存密码问题
问题环境
在Rails 7.0.3 + PostgreSQL环境下使用Devise 4.8.1搭建用户认证功能,前期操作如下:
- 执行
rails g devise:views生成Devise配套视图文件 - 执行
rails db:migrate完成数据库迁移操作
现有代码
User模型代码
class User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable, :confirmable has_many :posts, foreign_key: 'author_id' has_many :comments, foreign_key: 'author_id' has_many :likes, foreign_key: 'author_id' attr_accessor :password, :password_confirmation validates :name, presence: true validates :PostsCounter, presence: true, numericality: { greater_than_or_equal_to: 0 } def recent_posts posts.order(created_at: :desc).limit(3) end end
Devise相关数据库迁移代码
# frozen_string_literal: true class AddDeviseToUsers < ActiveRecord::Migration[7.0] def self.up change_table :users do |t| ## Database authenticatable t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at ## Trackable # t.integer :sign_in_count, default: 0, null: false # t.datetime :current_sign_in_at # t.datetime :last_sign_in_at # t.string :current_sign_in_ip # t.string :last_sign_in_ip ## Confirmable t.string :confirmation_token t.datetime :confirmed_at t.datetime :confirmation_sent_at t.string :unconfirmed_email # Only if using reconfirmable ## Lockable # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts # t.string :unlock_token # Only if unlock strategy is :email or :both # t.datetime :locked_at # Uncomment below if timestamps were not included in your original model. # t.timestamps null: false end add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true add_index :users, :confirmation_token, unique: true # add_index :users, :unlock_token, unique: true end def self.down # By default, we don't want to make any assumption about how to roll back a migration when your # model already existed. Please edit below which fields you would like to remove in this migration. raise ActiveRecord::IrreversibleMigration end end
问题描述
此前Devise功能运行正常,用户注册时密码会自动加密后存入数据库,目前出现异常:
- 用户完成注册后尝试登录时,系统提示邮箱或密码无效
- 核查PostgreSQL数据库发现,
encrypted_password字段未存入任何值 - 已尝试在线检索解决方案、重装相关gem,均未修复问题,暂不清楚问题成因
- 完整问题代码存放在项目feature/devise分支,排查需要更多代码信息可随时补充。
问题原因
核心问题是User模型中手动添加的attr_accessor :password, :password_confirmation覆盖了Devise原生逻辑。
Devise的database_authenticatable模块已经内置了这两个属性的处理逻辑:给password字段赋值时,模块会自动对明文密码做BCrypt哈希加密,将加密结果写入encrypted_password字段并持久化到数据库。手动定义的attr_accessor会把Devise的原生属性方法覆盖,导致密码赋值仅存储在普通Ruby实例变量中,完全不会触发加密写库流程,最终数据库里encrypted_password为空,登录校验自然无法通过。
修复方案
直接删除User模型里的attr_accessor :password, :password_confirmation这行代码,重启Rails服务后重新注册账号测试即可,加密后的密码会正常写入数据库,登录功能恢复正常。
内容的提问来源于stack exchange,提问作者Mirou
相关产品推荐
相关产品推荐

