glib-web 6.10.3 → 6.10.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4466ade33c7e7109a75befa19d22951379a4b57f0c20608b26ba80a9e539901b
4
- data.tar.gz: 9d05610c2feda72d878a64a44dec1f3cf8aa48c7f9237d2b3ce769d89beb9c8a
3
+ metadata.gz: af62a06f4071bb5b2779e61b2dfa771d9984d4f2f15bd6ed121fd71a676d7918
4
+ data.tar.gz: f5100fe92e6d2959a4479b82887e0009c0aaea1a2ef419f1ae6205c8fbda427b
5
5
  SHA512:
6
- metadata.gz: b2bbafdaaa9ddc994cafe76cc6520a3b8b7dd07e0ae456d666fe62ec061efd8f854f3e719d297d39146e6c0f259c80074f5b28655e2f898b5dbdc2ae243eb4aa
7
- data.tar.gz: aed913d8a8aeb19d81e0b01bde95480efe12ddbec54acd2095aed02fcb05e2753d57068c586faba341a2e6f282be41ec9b0e353951e881b853130e292d5a4ddd
6
+ metadata.gz: b0e19fa8b04dc2a7d44826f0c28eefe5411610d26226180dbd20079af4287177d44967331c56dd1c0dc7ebf0b3f01df08f1a38939958fe58c37a08183e8d10c0
7
+ data.tar.gz: 3c717ab4989d1e67f712d7d118d77cc6e99d136e0b1ed2e4e403a0974d0c364f705d064bad706b5f1bbfeca295333c523708e76f259a78cba969e958f6a494de
@@ -96,6 +96,18 @@ module Glib::Json::Libs
96
96
 
97
97
  json_ui_redirect_to url, status: status
98
98
  end
99
+ # Any other request format (e.g. a browser tab opening a protected file link
100
+ # `/temp_blobs/:id/report.pdf`, where the filename sets the format) used to raise
101
+ # ActionController::UnknownFormat -> a bare 406 with an empty body. Mirror the html
102
+ # branch instead: whatever opened the URL (browser tab, iframe, img) is redirected
103
+ # to the target, which the browser follows natively.
104
+ #
105
+ # MUST stay the LAST block. `negotiate_mime` answers `Accept: */*` requests with
106
+ # the FIRST declared format, so an `any` block placed before html would capture
107
+ # ordinary browser page loads and leave request.format as `*/*` for the action.
108
+ format.any do
109
+ redirect_to url
110
+ end
99
111
  end
100
112
  end
101
113
 
@@ -142,6 +154,17 @@ module Glib::Json::Libs
142
154
  redirect_to sign_in_url, **redirect_options
143
155
  end
144
156
  end
157
+ # Other non-HTML/JSON formats (a protected file link whose filename sets the
158
+ # request format, an XML export, ...) used to raise UnknownFormat -> a bare 406.
159
+ # Mirrors the csv branch: a clean gate status in test, a redirect in production.
160
+ # MUST stay the LAST block -- see glib_redirect_to.
161
+ format.any do
162
+ if Rails.env.test?
163
+ head :unauthorized
164
+ else
165
+ redirect_to sign_in_url, **redirect_options
166
+ end
167
+ end
145
168
  end
146
169
  end
147
170
 
@@ -185,6 +208,16 @@ module Glib::Json::Libs
185
208
  redirect_to user_default_url
186
209
  end
187
210
  end
211
+ # Other non-HTML/JSON formats -- mirrors the csv branch (clean gate status in
212
+ # test, redirect in production); previously raised UnknownFormat -> a bare 406.
213
+ # MUST stay the LAST block -- see glib_redirect_to.
214
+ format.any do
215
+ if Rails.env.test?
216
+ head :forbidden
217
+ else
218
+ redirect_to user_default_url
219
+ end
220
+ end
188
221
  end
189
222
  end
190
223
 
@@ -12,7 +12,9 @@ require 'hashdiff'
12
12
  # 4. ActiveStorage in diff_associations (convert Attached::One/Many to attachment records).
13
13
  # 5. same_as_before? derives from the computed diff instead of the instance-local
14
14
  # `snapshot_changed` flag (mapping-web's flag-gating silently dropped a target's
15
- # snapshot when taken after the owner's -- see "Snapshot ordering" below, issue #481).
15
+ # snapshot when taken after the owner's -- see "Snapshot ordering" below, issue #481),
16
+ # with the flag re-entering as a NEGATIVE signal for first snapshots only (see
17
+ # `same_as_before?` for why an empty association baseline cannot decide those).
16
18
  #
17
19
  # ## Snapshot ordering: owner vs association targets
18
20
  #
@@ -27,7 +29,8 @@ require 'hashdiff'
27
29
  # reading the target back through the association snapshots the persisted state instead.
28
30
  #
29
31
  # `snapshot_changed` / `attributes_before_save` remain writable instance accessors for
30
- # call-site use, but they are no longer consulted for the skip decision.
32
+ # call-site use; `snapshot_changed` is consulted by the skip decision only as a NEGATIVE
33
+ # signal on first snapshots (see `same_as_before?`).
31
34
  #
32
35
  # To get all records of a model, you can use the following query:
33
36
  # MyModel.joins(:snapshots).distinct
@@ -60,7 +63,16 @@ module Glib
60
63
  # Only set snapshot_changed if not already set (handles case where before_save
61
64
  # is called multiple times - e.g., when associated records are saved before parent)
62
65
  if snapshot_changed.nil?
63
- self.attributes_before_save = attributes_in_database
66
+ # For a save with no pending change `attributes_in_database` is empty -- an
67
+ # unchanged persisted record has no database-side delta -- which would make a
68
+ # first snapshot diff every attribute as an addition. Capture the full
69
+ # persisted state instead, so an unchanged save yields an empty item diff and
70
+ # the nil-guard keeps that baseline stable for later changes on the same
71
+ # instance. New records keep `attributes_in_database` (their all-nil
72
+ # originals): that non-empty baseline is exactly why a create's version 1
73
+ # records the full initial state. `unless` keeps the accessor nil, never
74
+ # `false`, for call-site nil-safety.
75
+ self.attributes_before_save = attributes_in_database.presence || (attributes unless new_record?)
64
76
  self.snapshot_changed = check_snapshot_changed
65
77
  end
66
78
  end
@@ -125,8 +137,10 @@ module Glib
125
137
  }
126
138
 
127
139
  # Don't create version if same as before. Reuses `calculated_diff` instead of
128
- # recomputing it inside `same_as_before?`.
129
- unless same_as_before?(calculated_diff)
140
+ # recomputing it inside `same_as_before?`. `version == 1` (no previous
141
+ # version exists) tells `same_as_before?` this is a FIRST snapshot, where the
142
+ # association baseline is empty and the flag carries decision weight.
143
+ unless same_as_before?(calculated_diff, first_snapshot: version == 1)
130
144
  # No nil guard: active_snapshot's `create_snapshot!` raises on failure and
131
145
  # always returns the snapshot.
132
146
  snapshot = create_snapshot!(**snapshot_obj)
@@ -186,13 +200,28 @@ module Glib
186
200
  end
187
201
 
188
202
  # Decides whether `glib_create_snapshot!` should skip the version write. Derived from
189
- # the computed diff (persisted state), never from the instance-local `snapshot_changed`
203
+ # the computed diff (persisted state), not from the instance-local `snapshot_changed`
190
204
  # flag: the flag dies with its instance, and an owner's snapshot replaces association
191
205
  # targets with fresh instances (`with_lock`'s reload clears the association cache, then
192
206
  # the diff walk re-reads the targets), so flag-gating used to silently drop a target's
193
- # follow-up snapshot taken through the association (issue #481). For a first snapshot
194
- # (no previous version) the diff runs current state against `attributes_before_save || {}`.
195
- def same_as_before?(computed_diff = diff)
207
+ # follow-up snapshot taken through the association (issue #481).
208
+ #
209
+ # The one place the flag still decides: a FIRST snapshot whose association diff is
210
+ # meaningless. With no previous version, `fetch_snapshot_items(nil)` returns `{}`
211
+ # for associations, so every pre-existing child row reads as `+` and the diff alone
212
+ # can never prove a no-op — any never-snapshotted record with children would mint a
213
+ # version on every snapshot call (observed as spurious "Edited" audit entries on
214
+ # routine re-saves). There the flag is consulted as a NEGATIVE signal:
215
+ # - `false` — this instance crossed the before_save boundary and
216
+ # `check_snapshot_changed` found no item or child change, and the item diff is
217
+ # net-zero against `attributes_before_save` => skip;
218
+ # - `nil` — no save boundary on this instance (an owner-triggered snapshot of a
219
+ # replaced association target, issue #481) => mint;
220
+ # - `true` — a change was detected at the save boundary; falls through to the
221
+ # diff-based decision (a reverted change still no-ops).
222
+ def same_as_before?(computed_diff = diff, first_snapshot: false)
223
+ return true if first_snapshot && snapshot_changed == false && computed_diff['item'].blank?
224
+
196
225
  item_unchanged = computed_diff['item'].blank?
197
226
  assoc_diff = computed_diff['associations']
198
227
  associations_unchanged = assoc_diff.nil? || assoc_diff.values.all?(&:blank?)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glib-web
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.10.3
4
+ version: 6.10.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-16 00:00:00.000000000 Z
11
+ date: 2026-09-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activestorage