inline_forms 8.1.11 → 8.1.15
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 +36 -0
- data/app/controllers/inline_forms_controller.rb +104 -48
- data/app/views/inline_forms/row_destroyed.html.erb +1 -1
- 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: 58e6670831f8bce627752b9797371fb20d2f3b14f571a4bc8c879478b71f5ff6
|
|
4
|
+
data.tar.gz: 32fd5f2f3503126e9113d10a3bea9ba23468667f11cc4db8252d78078b101af8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d9e59af7820b05e5ef046c1771a85f37ee1d7dd4ab9affbe0f8e2dfda03fe49db57d9452972406a889f699732165b8117bb56ecdee6c6a5edf9c05b0d14642f8
|
|
7
|
+
data.tar.gz: 55be4d675321e511079de4a362688b664e65dce704dd56ef5929c8db2a286f0fef034312a2572016138808155a18e4f7150472a26aa904adb65e926d762da949
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,42 @@ All notable changes to this project are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [8.1.15] - 2026-05-28
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **Post-delete undo on Apartment/Photo (and any model with `rich_text`) left `description` empty.** Undo only reified the parent row; ActionText bodies live in `action_text_rich_texts` and are removed on `destroy`, with separate PaperTrail `destroy` versions. `revert` now also reifies and saves each `ActionText::RichText` destroy snapshot that belonged to the restored parent (Apartment, nested Photo, `FormElementShowcase#description`, etc.).
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **Regression tests:** apartment row destroy+undo with `description` rich text; nested photo destroy+undo with `description` rich text.
|
|
16
|
+
|
|
17
|
+
## [8.1.14] - 2026-05-28
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- **`example_app_showcase_row_turbo_test` broke `--example` installs.** The Empty-demo undo regression parsed the undo URL as `/revert/:id`, but member routes are `/form_element_showcases/:id/revert`. The installer gate failed (`131 runs, 1 failure`) and surfaced the misleading “Rails could not create the app 'MyApp', maybe because it is a reserved word…” message even though the app was generated. The test now matches the real path and loads the destroy version from PaperTrail.
|
|
22
|
+
|
|
23
|
+
## [8.1.13] - 2026-05-28
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- **Post-delete undo restored the wrong PaperTrail version.** `destroy` stored `@undo_version = @object.versions.last` *before* `destroy`, so the undo link targeted the latest **update** (e.g. a `plain_text_area` edit). `revert` then reified that update — the state *before* the edit — so fields like `body_plain_area` on "Empty demo" came back blank. `@undo_version` is now taken after destroy so undo always targets the `destroy` event snapshot.
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- **Regression test** on `FormElementShowcase` "Empty demo": edit `body_plain_area`, delete, undo, assert text and undo URL use the destroy version.
|
|
32
|
+
|
|
33
|
+
## [8.1.12] - 2026-05-28
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
|
|
37
|
+
- **`InlineFormsController#revert` and CanCan `check_authorization`.** `revert` is excluded from `load_and_authorize_resource`, but `authorize!` only ran on some branches — and after `return unless @parent`, so a nil PaperTrail `item` on a destroyed row (or any path that bailed out early) left `@_authorized` unset and raised `CanCan::AuthorizationNotPerformed`. Authorization now runs once at the top of the action via `revert_authorization_subject` (reified record, `ActionText::RichText` parent, live `item`, or an id-only stub for destroyed rows). The post-delete **undo** link in `row_destroyed.html.erb` now requests `turbo_stream` like the versions-panel Restore link, matching the `format.turbo_stream` response.
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- **Regression test** `example_app_showcase_row_turbo_test.rb`: destroy + undo revert on `FormElementShowcase`.
|
|
42
|
+
|
|
7
43
|
## [8.1.11] - 2026-05-28
|
|
8
44
|
|
|
9
45
|
### Fixed
|
|
@@ -247,8 +247,10 @@ class InlineFormsController < ApplicationController
|
|
|
247
247
|
@update_span = params[:update]
|
|
248
248
|
@object = referenced_object
|
|
249
249
|
if current_user.role? :superadmin
|
|
250
|
-
@undo_version = @object.versions.last
|
|
251
250
|
@object.destroy
|
|
251
|
+
# Capture after destroy: `.last` before destroy was the latest *update*
|
|
252
|
+
# (e.g. a plain_text_area edit), so undo reified the pre-edit state.
|
|
253
|
+
@undo_version = @object.versions.last
|
|
252
254
|
respond_to do |format|
|
|
253
255
|
format.html { render_row_turbo_destroyed } if row_html_turbo_allowed?
|
|
254
256
|
end
|
|
@@ -270,62 +272,116 @@ class InlineFormsController < ApplicationController
|
|
|
270
272
|
# below derive from `@parent` for both branches.
|
|
271
273
|
def revert
|
|
272
274
|
@update_span = params[:update]
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
authorize!(:revert, @parent) if cancan_enabled?
|
|
302
|
-
end
|
|
303
|
-
return unless row_html_turbo_allowed?
|
|
304
|
-
respond_to do |format|
|
|
305
|
-
format.turbo_stream { render_revert_turbo_streams }
|
|
306
|
-
end
|
|
307
|
-
return
|
|
308
|
-
end
|
|
309
|
-
if defined?(ActionText::RichText) && @object.is_a?(ActionText::RichText)
|
|
310
|
-
@rich_text_record = @object
|
|
275
|
+
@version = PaperTrail::Version.find(params[:id])
|
|
276
|
+
@parent = revert_authorization_subject(@version)
|
|
277
|
+
authorize!(:revert, @parent || @Klass) if cancan_enabled?
|
|
278
|
+
return head :forbidden unless current_user.role? :superadmin
|
|
279
|
+
return head :not_found unless @parent
|
|
280
|
+
|
|
281
|
+
@object = @version.reify(
|
|
282
|
+
has_many: true,
|
|
283
|
+
has_and_belongs_to_many: true,
|
|
284
|
+
belongs_to: true
|
|
285
|
+
)
|
|
286
|
+
# PaperTrail::Version#reify returns nil for `create` events because
|
|
287
|
+
# there is no prior state to roll back to. The versions list view
|
|
288
|
+
# hides the Restore link for `create` rows, but guard here too in
|
|
289
|
+
# case a request was bookmarked or replayed: render close on the
|
|
290
|
+
# current parent without mutating anything.
|
|
291
|
+
if @object.nil?
|
|
292
|
+
# reify returns nil for `create` events (no prior state). For a
|
|
293
|
+
# rich_text create, reverting means "undo the creation" -> destroy
|
|
294
|
+
# the ActionText::RichText row so the parent's field reverts to
|
|
295
|
+
# empty (symmetric with reverting an update on a rich_text that
|
|
296
|
+
# was first saved empty). For a primary record we never offer
|
|
297
|
+
# Restore on `create` in the view; this branch only runs for
|
|
298
|
+
# replayed/bookmarked URLs and must remain a no-op response keyed
|
|
299
|
+
# off the parent.
|
|
300
|
+
item = @version.item
|
|
301
|
+
if defined?(ActionText::RichText) && item.is_a?(ActionText::RichText)
|
|
302
|
+
@rich_text_record = item
|
|
311
303
|
@parent = @rich_text_record.record
|
|
312
|
-
@
|
|
304
|
+
return head :not_found unless @parent
|
|
305
|
+
@rich_text_record.destroy
|
|
313
306
|
@parent.touch if @parent.respond_to?(:touch)
|
|
314
307
|
else
|
|
315
|
-
@parent = @
|
|
316
|
-
@parent
|
|
317
|
-
end
|
|
318
|
-
authorize!(:revert, @parent) if cancan_enabled?
|
|
319
|
-
return unless row_html_turbo_allowed?
|
|
320
|
-
|
|
321
|
-
respond_to do |format|
|
|
322
|
-
format.turbo_stream { render_revert_turbo_streams }
|
|
308
|
+
@parent = item || @parent
|
|
309
|
+
return head :not_found unless @parent
|
|
323
310
|
end
|
|
311
|
+
return render_revert_response if row_html_turbo_allowed?
|
|
312
|
+
return
|
|
313
|
+
end
|
|
314
|
+
if defined?(ActionText::RichText) && @object.is_a?(ActionText::RichText)
|
|
315
|
+
@rich_text_record = @object
|
|
316
|
+
@parent = @rich_text_record.record
|
|
317
|
+
return head :not_found unless @parent
|
|
318
|
+
@rich_text_record.save!
|
|
319
|
+
@parent.touch if @parent.respond_to?(:touch)
|
|
320
|
+
else
|
|
321
|
+
@parent = @object
|
|
322
|
+
@parent.save!
|
|
323
|
+
restore_rich_texts_for_reverted_parent!(@parent)
|
|
324
|
+
@parent.reload
|
|
324
325
|
end
|
|
326
|
+
render_revert_response if row_html_turbo_allowed?
|
|
325
327
|
end
|
|
326
328
|
|
|
327
329
|
private
|
|
328
330
|
|
|
331
|
+
# Undoing a parent +destroy+ reifies the Apartment/Photo row only. ActionText
|
|
332
|
+
# bodies live in +action_text_rich_texts+ and get their own PaperTrail
|
|
333
|
+
# +destroy+ versions; those rows are gone after +parent.destroy+, so we also
|
|
334
|
+
# reify and save each matching +ActionText::RichText+ destroy snapshot.
|
|
335
|
+
def restore_rich_texts_for_reverted_parent!(parent)
|
|
336
|
+
return unless defined?(ActionText::RichText)
|
|
337
|
+
|
|
338
|
+
record_type = parent.class.base_class.name
|
|
339
|
+
record_id = parent.id
|
|
340
|
+
|
|
341
|
+
PaperTrail::Version.where(item_type: "ActionText::RichText", event: "destroy").find_each do |version|
|
|
342
|
+
attrs = version.object_deserialized
|
|
343
|
+
next unless attrs.is_a?(Hash)
|
|
344
|
+
|
|
345
|
+
type = attrs["record_type"] || attrs[:record_type]
|
|
346
|
+
rid = attrs["record_id"] || attrs[:record_id]
|
|
347
|
+
next unless type == record_type && rid.to_i == record_id
|
|
348
|
+
|
|
349
|
+
rich_text = version.reify
|
|
350
|
+
rich_text&.save!
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
# +revert+ is excluded from +load_and_authorize_resource+; +authorize!+ runs in the
|
|
355
|
+
# action. +check_authorization+ on ApplicationController still requires that flag.
|
|
356
|
+
def revert_authorization_subject(version)
|
|
357
|
+
reified = version.reify(
|
|
358
|
+
has_many: true,
|
|
359
|
+
has_and_belongs_to_many: true,
|
|
360
|
+
belongs_to: true
|
|
361
|
+
)
|
|
362
|
+
if defined?(ActionText::RichText) && reified.is_a?(ActionText::RichText)
|
|
363
|
+
return reified.record
|
|
364
|
+
end
|
|
365
|
+
return reified if reified
|
|
366
|
+
|
|
367
|
+
item = version.item
|
|
368
|
+
if defined?(ActionText::RichText) && item.is_a?(ActionText::RichText)
|
|
369
|
+
return item.record
|
|
370
|
+
end
|
|
371
|
+
return item if item
|
|
372
|
+
|
|
373
|
+
klass = version.item_type.safe_constantize
|
|
374
|
+
return nil unless klass && version.item_id
|
|
375
|
+
|
|
376
|
+
klass.new(id: version.item_id)
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
def render_revert_response
|
|
380
|
+
respond_to do |format|
|
|
381
|
+
format.turbo_stream { render_revert_turbo_streams }
|
|
382
|
+
end
|
|
383
|
+
end
|
|
384
|
+
|
|
329
385
|
# Versions list lives in +<turbo-frame id="…_versions">+; POST +restore+ would otherwise
|
|
330
386
|
# send +Turbo-Frame: …_versions+ while +row_close+ only returns the row frame. Stream
|
|
331
387
|
# replaces both the row and the versions panel in one response.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<div class="small-12 column">
|
|
4
4
|
<%= link_to t("inline_forms.view.undo"),
|
|
5
5
|
send("revert_#{@Klass.to_s.underscore}_path", @undo_version, update: @update_span),
|
|
6
|
-
inline_forms_turbo_link_data(@update_span, method: :post).merge(class: "button") %>
|
|
6
|
+
inline_forms_turbo_link_data(@update_span, method: :post, turbo_stream: true).merge(class: "button") %>
|
|
7
7
|
</div>
|
|
8
8
|
</div>
|
|
9
9
|
</turbo-frame>
|
data/lib/inline_forms/version.rb
CHANGED