Add reset when UnknownAttributeError is hit
What does this MR do and why?
Sometimes our codebase on prod is already loaded when the database migrations are run underneath, and the attributes
method, when run against an existing record gets the latest DB colummn SQL query returns new columns that ActiveRecord doesn't know about.
It raises an ActiveModel::UnknownAttributeError
We have prior art and a feature flag to perform a reset on the columns when this occurs with StatementInvalid
error, with a specific error message in !124009 (merged).
This MR expands that class to also accept ActiveRecord::UnknownAttributeError
. It retains the same condition (feature flag, not within 10 minutes of a previous reset).
To reproduce
Here's how you can test it locally. Use two terminals, one with rails console
and one with postgres
.
Start with master
branch and a DB that hasn't got the column. I've used MemberRole
as an example but you can use any table or column, even made up nonsense column names. Go wild
-
Start
rails c
in one terminal and callMemberRole.new.attributes
. You shouldn't see the new column in that list (it's pulling from the cache - no SQL call). You can also callMemberRole.column_names
to get this list. -
MemberRole.last.attributes
(or create one if there isn't one). I didn't have any on my local so I did
m = MemberRole.create(namespace: Namespace.first, description: "test", base_access_level: "guest")
- In a second terminal, open
gdk psql
console, add the column to your DB (not via your migration). This simulates the DB migration happening on a different environment (say canary).
ALTER TABLE "member_roles" ADD "admin_merge_request" boolean DEFAULT FALSE NOT NULL;
-
Back in your console, call
MemberRole.last.attributes
. The new column is in the list now (because it made an SQL call). But if I callMemberRole.new.attributes
orMemberRole.column_list
, it's not there. That's because it's pulling from the ActiveRecord cache with an outdated column list. -
To simulate this error, do:
> MemberRole.new(MemberRole.last.attributes)
MemberRole Load (6.5ms) SELECT "member_roles".* FROM "member_roles" ORDER BY "member_roles"."id" DESC LIMIT 1
ActiveModel::UnknownAttributeError: unknown attribute 'admin_merge_request' for MemberRole.
raise UnknownAttributeError.new(self, k.to_s)
^^^^^
from /Users/charlie/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activemodel-7.0.6/lib/active_model/attribute_assignment.rb:51:in `_assign_attribute'
- don't forget to remove the column in your psql.
ALTER TABLE "member_roles" DROP COLUMN "admin_merge_request";
MR acceptance checklist
This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.
-
I have evaluated the MR acceptance checklist for this MR.