I got my application to weird state - when I create record (in application or in console), it is created in database, object reports to be persisted, but the object has no id (id: nil
).
In summary: Creating any objects in my app is corrupted, as they don't get id back from database.
I'm not sure when this change happened, as automatic tests are working without a hitch. By switching to older commits, it seems like the change is in upgrade from Rails 7.1.1 to Rails 7.2.0 (or at least when I switch to old commit with 7.1.3.4, it works, and when I either use commit with 7.2, or manually update to 7.2.0, everything stops working).
I read through the ActiveRecord 7.2 changelog, but didn't stumble onto anything that would help me.
There are almost no other gems changing with this update, so Rails 7.2 seems to have something with it..
Note: I only did bundle install, not app:update
in my experiments. Switching to commit after update is applied by script and manual merging leads to same situation.
In summary: Going back to old commit on Rails 7.1.1.1 makes things work. Upgrading up to 7.1.5.1 is ok. Updating gems to 7.2.0 (and even 7.2.0beta1) breaks it
I tried using both mysql2
and trilogy
adapter to same result.
I tested the problem with multiple models, in web interface and in console. I was able to work correctly with models generated by gem Notice
.
I suspect it might be some problem with database (MariaDB Server version: 8.0.40 MySQL Community Server - GPL), but I have no proof for that.
I checked for differences between my table that's not working, and the table that is.
Columns (both using autoincrementing id BIGINT), indexes (both having it correctly as PRIMARY KEY), everything is the same. Only difference I found was in collation, my table using utf8mb4_general_ci
, and the "working one" utf8mb4_0900_ai_ci
.
I use collation: utf8mb4_general_ci
in my database.yml
, so this doesn't seem to me like a lead.
Also relevant might be that I'm migrating from different (Python) app, and so my database is mainly created by importing db dump and running some migrations on that.
I'm getting little crazy being stuck on this, so any help or ideas on where to look are very appreciated!
Code:
I have this class (simplified to minimum for experimentation, also tried with other classes to same results):
# 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
And create (inside rails console) with:
a = Announcement.new(name: "Test", text_body: "aaa", created_by: 1, owned_by_group: 1)
(created_by
and owned_by_group
being required fields in db)
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
myappdev)> 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)
Ok, this seems bit crazy, but solution is to move id
column to be first column in table.
This is of course default when creating new tables in Rails, but as I was importing data from legacy application, it didn't follow this structure.