inline_forms 8.1.15 → 8.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/app/controllers/inline_forms_controller.rb +63 -11
- data/lib/inline_forms/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b7336d7c761e22dd4378a0c2d01b54f7558a2a29d9818a085b4478c17e664ead
|
|
4
|
+
data.tar.gz: 3e08954932efda044a18cf4f4a68ad3299ffdb382581c9369bc733023ff57906
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 93339e380b5d224fe1b1d3b5459cc6675682ed81bd87f7a28594afafaa9304b50467dc8cb2b628641c78fb39ba68649c02fd9a38b154388815458e51e2781afe
|
|
7
|
+
data.tar.gz: e33e98b2676db0ec7d0af1196a1bf9be4b423b231d52f9636391fd830fdb29779a6e03381a5150bdde4258374ec13c4ad3b908f55cdd1e3ebf2d03ad86ac2cbc
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,26 @@ All notable changes to this project are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [8.1.17] - 2026-05-28
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **`RecordNotUnique` on `photos.id` (and any primary record) when restoring a `destroy` version while the row still exists.** PaperTrail records a non-empty changeset for `destroy` events, so the versions panel shows a Restore link on `destroy` rows. Reverting a `destroy` reifies a record with the original primary key and `new_record? == true`; the normal undo (row currently deleted) path correctly INSERTs it, but once the row had already been restored a blind `save!` re-INSERTed the existing id and raised `SQLite3::ConstraintException: UNIQUE constraint failed: photos.id`. `revert` now upserts the primary record by PK (mirroring the 8.1.16 rich-text fix): when a row with that id already exists, the reified column values are copied onto it and saved in place, so restoring a `destroy` version is idempotent across repeated delete/undo cycles.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **Regression test:** restore a Photo `destroy` version while the row still exists (panel Restore / replayed undo) must not raise `RecordNotUnique`.
|
|
16
|
+
|
|
17
|
+
## [8.1.16] - 2026-05-28
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- **`RecordNotUnique` on `action_text_rich_texts.id` when undoing a delete more than once.** Restoring rich text after parent undo used `reify.save!`, which INSERTs the old primary key. A second delete/undo cycle (or an already-restored row) hit SQLite's unique constraint. Restoration now upserts by `(record_type, record_id, name)` and copies `body` only, and only the latest PaperTrail `destroy` version per attribute is applied.
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- **Regression test:** nested Photo delete → undo → delete → undo.
|
|
26
|
+
|
|
7
27
|
## [8.1.15] - 2026-05-28
|
|
8
28
|
|
|
9
29
|
### Fixed
|
|
@@ -318,8 +318,7 @@ class InlineFormsController < ApplicationController
|
|
|
318
318
|
@rich_text_record.save!
|
|
319
319
|
@parent.touch if @parent.respond_to?(:touch)
|
|
320
320
|
else
|
|
321
|
-
@parent = @object
|
|
322
|
-
@parent.save!
|
|
321
|
+
@parent = persist_reverted_primary!(@object)
|
|
323
322
|
restore_rich_texts_for_reverted_parent!(@parent)
|
|
324
323
|
@parent.reload
|
|
325
324
|
end
|
|
@@ -328,26 +327,79 @@ class InlineFormsController < ApplicationController
|
|
|
328
327
|
|
|
329
328
|
private
|
|
330
329
|
|
|
330
|
+
# Persist a reified *primary* record (Apartment, Photo, ...) for +revert+.
|
|
331
|
+
#
|
|
332
|
+
# +reify+ on a +destroy+ version returns a record with +new_record? == true+
|
|
333
|
+
# carrying the original primary key. The normal undo (row currently deleted)
|
|
334
|
+
# path INSERTs that id and is correct. But the versions panel also offers
|
|
335
|
+
# Restore on +destroy+ rows (their changeset is non-empty in apps that track
|
|
336
|
+
# +object_changes+ on destroy), and the post-delete undo banner can be
|
|
337
|
+
# replayed. Once the row has been restored, a blind +save!+ re-INSERTs the
|
|
338
|
+
# existing id and raises +RecordNotUnique+ (SQLite: +UNIQUE constraint failed:
|
|
339
|
+
# photos.id+). Mirror the rich-text upsert (8.1.16): when a row with that PK
|
|
340
|
+
# already exists, copy the reified column values onto it and +save!+ that
|
|
341
|
+
# instead, so reverting is idempotent across repeated delete/undo cycles.
|
|
342
|
+
def persist_reverted_primary!(object)
|
|
343
|
+
klass = object.class
|
|
344
|
+
primary_key = klass.primary_key
|
|
345
|
+
|
|
346
|
+
if object.new_record? && object.id.present? && klass.exists?(object.id)
|
|
347
|
+
existing = klass.find(object.id)
|
|
348
|
+
existing.assign_attributes(object.attributes.except(primary_key))
|
|
349
|
+
existing.save!
|
|
350
|
+
existing
|
|
351
|
+
else
|
|
352
|
+
object.save!
|
|
353
|
+
object
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
|
|
331
357
|
# Undoing a parent +destroy+ reifies the Apartment/Photo row only. ActionText
|
|
332
358
|
# bodies live in +action_text_rich_texts+ and get their own PaperTrail
|
|
333
359
|
# +destroy+ versions; those rows are gone after +parent.destroy+, so we also
|
|
334
|
-
# reify
|
|
360
|
+
# reify each matching +ActionText::RichText+ destroy snapshot.
|
|
361
|
+
#
|
|
362
|
+
# Use +find_or_initialize_by(record_type, record_id, name)+ and copy +body+
|
|
363
|
+
# only. Reified rows carry the old PK; +save!+ on a new record would INSERT
|
|
364
|
+
# that id and raise +RecordNotUnique+ on a second delete/undo cycle when the
|
|
365
|
+
# row already exists. Only the newest destroy version per attribute name is
|
|
366
|
+
# applied (repeat delete/undo leaves multiple RT destroy versions in the table).
|
|
335
367
|
def restore_rich_texts_for_reverted_parent!(parent)
|
|
336
368
|
return unless defined?(ActionText::RichText)
|
|
337
369
|
|
|
338
370
|
record_type = parent.class.base_class.name
|
|
339
371
|
record_id = parent.id
|
|
372
|
+
versions_by_name = {}
|
|
373
|
+
|
|
374
|
+
PaperTrail::Version
|
|
375
|
+
.where(item_type: "ActionText::RichText", event: "destroy")
|
|
376
|
+
.order(id: :desc)
|
|
377
|
+
.each do |version|
|
|
378
|
+
attrs = version.object_deserialized
|
|
379
|
+
next unless attrs.is_a?(Hash)
|
|
340
380
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
381
|
+
type = attrs["record_type"] || attrs[:record_type]
|
|
382
|
+
rid = attrs["record_id"] || attrs[:record_id]
|
|
383
|
+
next unless type == record_type && rid.to_i == record_id
|
|
344
384
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
385
|
+
name = (attrs["name"] || attrs[:name]).to_s
|
|
386
|
+
next if name.empty?
|
|
387
|
+
|
|
388
|
+
versions_by_name[name] ||= version
|
|
389
|
+
end
|
|
348
390
|
|
|
349
|
-
|
|
350
|
-
|
|
391
|
+
versions_by_name.each_value do |version|
|
|
392
|
+
reified = version.reify
|
|
393
|
+
next unless reified
|
|
394
|
+
|
|
395
|
+
name = reified.name.to_s
|
|
396
|
+
record = ActionText::RichText.find_or_initialize_by(
|
|
397
|
+
record_type: record_type,
|
|
398
|
+
record_id: record_id,
|
|
399
|
+
name: name
|
|
400
|
+
)
|
|
401
|
+
record.body = reified.body if reified.respond_to?(:body)
|
|
402
|
+
record.save!
|
|
351
403
|
end
|
|
352
404
|
end
|
|
353
405
|
|
data/lib/inline_forms/version.rb
CHANGED