Open
Conversation
Previously, if the redirects feature was enabled but the redirects database table couldn't be queried (most often because the migration hadn't been run yet), saving or deleting a work produced a 500 — even though the work itself had already been saved successfully. This commit catches that error and surfaces it as a clean failure instead. The work save still succeeds; only the redirect bookkeeping is skipped for that request. Redirects are a sidecar to the work, not load-bearing for it, so a soft fail is the right outcome. Also renames "ledger" terminology to "redirects table" throughout the related code and docs for clearer language.
Centralizes redirect path normalization on the work and collection resources themselves so any save — form, console, importer, change-set apply — produces canonical paths without callers having to remember. The read-side consumers (indexer, sync step) no longer re-normalize and trust the persisted shape. Normalization still runs at the points where unfamiliar input arrives from outside the resource: the form populator (so a user pasting a DSpace URL gets a friendly form experience), the redirect resolver (so /foo/ and /foo both match), and the redirect lookup service (so callers can pass any reasonable path form).
Test Results 17 files ± 0 17 suites ±0 3h 25m 21s ⏱️ - 4m 33s Results for commit a9c9524. ± Comparison against base commit cae6920. This pull request removes 436 and adds 448 tests. Note that renamed tests count towards both. |
orangewolf
previously approved these changes
May 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Details
Until now, every consumer of the redirects feature had its own normalization call: the form populator, the indexer, the sync step, the resolver, and the lookup service all ran the same
RedirectPathNormalizerindependently. The duplication worked, but it was fragile — anyone adding a new code path that wrote redirects had to remember to normalize, and any console write or non-form importer that bypassed the populator could quietly persist non-canonical data.This change makes the resource itself the source of truth for canonical form. A new
Hyrax::RedirectsNormalizationconcern is included onHyrax::WorkandHyrax::PcdmCollectionand normalizes redirect path entries on assignment, working under both flexible-metadata modes. Read-side consumers (indexer, sync step) no longer re-normalize and trust the persisted shape.Normalization still runs at the points where unfamiliar input arrives from outside the resource — the form populator (so a user pasting a DSpace URL gets a friendly form experience), the redirect resolver (so
/foo/and/fooboth match), and the redirect lookup service (so callers can pass any reasonable path form).Testing
work.redirects = [{path: '/foo/'}]; persister.save(resource: work)) and confirm the persisted entry is normalized to/foo.https://old.example.edu/handle/123?utm=email) and confirm it persists as/handle/123and resolves correctly when visited./foo/(with trailing slash) for a redirect persisted as/fooand confirm the resolver matches it.HYRAX_FLEXIBLE=falseandHYRAX_FLEXIBLE=trueand confirm the form, console-write, and resolver behaviors above hold in each mode.