Is it possible to ignore an attribute?
supercobra opened this issue · 3 comments
I know about nullify, but I would like to ignore an attribute all together. This is needed when cloning an object that contains a full text search field (TS_VECTOR) like we have when using Postgresql full text search.
How will ignore differ from nullify? Can you please provide an example?
Nullify will save a null value into the new record. Postgres full text search fields are updated (set) automatically by Postgres and do not accept null update. This generates an error.
Example:
This checklists
table as a full text search fields searchable
(last one). The content of this field is autogenerated by Postgres when creating or updating a record.
Table "public.checklists"
Column | Type | Collation | Nullable | Default
-----------------------+-----------------------------+-----------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
id | bigint | | not null | nextval('checklists_id_seq'::regclass)
type | character varying(55) | | not null |
title | character varying(256) | | not null |
description | character varying | | |
is_completed | boolean | | not null | false
...
...
completion_percentage | integer | | not null | 0
searchable | tsvector | | | generated always as (setweight(to_tsvector('english'::regconfig, COALESCE(title, ''::character varying)::text), 'A'::"char") || setweight(to_tsvector('english'::regconfig, COALESCE(description, ''::character varying)::text), 'B'::"char")) stored
If we update to nil we get an error. First let's load the record with the console:
$ rails console
Loading development environment (Rails 6.1.3.2)
[1] pry(main)> checklist = Checklist.first
Checklist Load (2.5ms) SELECT "checklists".* FROM "checklists" ORDER BY "checklists"."id" ASC LIMIT $1 [["LIMIT", 1]]
=> #<ChecklistTemplate:0x000000010f6a7b28>
Then we set the field to nil to simulate clowne nullify
system and we save we have an error:
[2] pry(main)> c.searchable=nil
=> nil
[3] pry(main)> c.save
TRANSACTION (0.6ms) BEGIN
Project Load (1.3ms) SELECT "projects".* FROM "projects" WHERE "projects"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
ChecklistTemplate Update (2.6ms) UPDATE "checklists" SET "updated_at" = $1, "searchable" = $2 WHERE "checklists"."id" = $3 [["updated_at", "2023-05-20 16:54:04.457417"], ["searchable", nil], ["id", 1]]
TRANSACTION (0.5ms) ROLLBACK
ActiveRecord::StatementInvalid: PG::GeneratedAlways: ERROR: column "searchable" can only be updated to DEFAULT
DETAIL: Column "searchable" is a generated column.
from /Users/supercobra/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/rack-mini-profiler-3.1.0/lib/patches/db/pg.rb:69:in `exec_params'
Caused by PG::GeneratedAlways: ERROR: column "searchable" can only be updated to DEFAULT
DETAIL: Column "searchable" is a generated column.
Hence the need to be able to ignore an attribute since nullify does not work in this case.
Thanks for the details; they're very helpful.
I think, in this case, defining an after_clone
callback with the restore_attributes(%w[searchable])
should do the trick (restore_attributes docs).