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

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_ci vs utf8mb4_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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 03:02:25