ActiveRecord保存后无法获取ID问题排查求助
Rails 7.2.0 创建记录后对象ID为nil(记录已写入数据库)的问题排查与解决
问题现象
升级Rails从7.1.x到7.2.0后,出现以下异常:
- 在应用或控制台创建记录时,数据已成功写入数据库,对象
persisted?返回true,但对象的id字段始终为nil - 回退到Rails 7.1.x版本后问题完全消失
- 测试
mysql2和trilogy数据库适配器,结果一致 - 部分由Notice gem生成的模型可正常工作
- 数据库为MariaDB 8.0.40,异常数据表使用自增BIGINT类型的
id作为主键,与正常工作的数据表仅排序规则不同(utf8mb4_general_civsutf8mb4_0900_ai_ci),但database.yml配置的是utf8mb4_general_ci - 数据库由Python应用迁移而来,通过导入备份并执行Rails迁移创建
相关代码与输出
模型代码
# models/announcement.rb class Announcement < ApplicationRecord self.table_name = 'information' end
schema.rb片段
create_table "information", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| t.datetime "created_at", precision: nil, default: -> { "CURRENT_TIMESTAMP" }, null: false t.datetime "updated_at", precision: nil t.string "name", null: false t.text "text_body" t.text "text_body_html" t.bigint "owned_by_group", null: false t.bigint "created_by", null: false t.bigint "updated_by" t.index ["created_by"], name: "fk_information_created_by_members" t.index ["owned_by_group"], name: "ix_information_owned_by_group" t.index ["updated_by"], name: "fk_information_updated_by_members" end
控制台操作输出
myapp(dev)> an = Announcement.new(name: "Test", text_body: "aaa", created_by: 1, owned_by_group: 1) myapp(dev)> an.valid? => true myapp(dev)> an.save TRANSACTION (0.5ms) BEGIN Announcement Create (1.5ms) INSERT INTO `information` (`created_at`, `updated_at`, `name`, `text_body`, `text_body_html`, `owned_by_group`, `created_by`, `updated_by`) VALUES ('2025-01-04 20:35:10', '2025-01-04 20:35:10', 'Test', 'aaa', NULL, 1, 1, NULL) TRANSACTION (4.2ms) COMMIT => true myapp(dev)> an => #<Announcement:0x00007f40d7ac4e18 created_at: "2025-01-04 21:35:10.000000000 +0100", updated_at: "2025-01-04 21:35:10.000000000 +0100", id: nil, name: "Test", text_body: "aaa", text_body_html: nil, owned_by_group: 1, created_by: 1, updated_by: nil> myapp(dev)> an.persisted? => true myapp(dev)> an.id => nil myapp(dev)> an.reload Announcement Load (0.5ms) SELECT `information`.* FROM `information` WHERE `information`.`id` IS NULL LIMIT 1 (myapp):11:in `<main>': Couldn't find Announcement with [WHERE `information`.`id` IS NULL] (ActiveRecord::RecordNotFound)
可能原因
Rails 7.2对数据库主键的获取逻辑进行了调整,对于非Rails原生创建的表(如从Python应用迁移导入的表),可能无法正确识别自增主键的返回值;同时数据表排序规则与配置不一致,可能导致ActiveRecord读取字段元数据时出现异常。
解决方案
1. 显式指定主键字段及类型
在模型中明确声明主键信息,确保ActiveRecord正确识别:
# models/announcement.rb class Announcement < ApplicationRecord self.table_name = 'information' self.primary_key = 'id' attribute :id, :bigint end
2. 检查表的自增主键配置
通过SQL确认表的id字段确实为自增主键:
SHOW CREATE TABLE information;
确保输出包含id BIGINT NOT NULL AUTO_INCREMENT,且主键约束配置正确。
3. 同步表排序规则与配置
执行SQL修改表的排序规则,与database.yml配置保持一致:
ALTER TABLE information CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
修改完成后重新生成schema文件:
rails db:schema:dump
4. 更新数据库适配器版本
确保使用的数据库适配器为兼容Rails 7.2的最新版本:
# Gemfile gem 'mysql2', '~> 0.5.6' # 或最新兼容版本 # 或使用trilogy gem 'trilogy', '~> 2.4.0'
执行更新:
bundle update mysql2 # 或 bundle update trilogy
5. 禁用Rails 7.2新主键获取回调
若以上方法无效,可尝试禁用Rails 7.2新增的主键获取回调:
class Announcement < ApplicationRecord self.table_name = 'information' skip_callback :create, :after, :fetch_new_record_primary_key, if: -> { Rails.version >= '7.2' } end
验证
修改完成后,在控制台重新测试创建记录,检查id字段是否正常赋值,执行reload是否能成功获取记录。
内容的提问来源于stack exchange,提问作者janpeterka
相关产品推荐
相关产品推荐

