Skip to content

Make find/exists? resolve semantic work package identifiers#22718

Open
akabiru wants to merge 8 commits intodevfrom
feature/73756-adapt-routes-for-project-based-semantic-work-package-identifiers
Open

Make find/exists? resolve semantic work package identifiers#22718
akabiru wants to merge 8 commits intodevfrom
feature/73756-adapt-routes-for-project-based-semantic-work-package-identifiers

Conversation

@akabiru
Copy link
Copy Markdown
Member

@akabiru akabiru commented Apr 10, 2026

Ticket

https://community.openproject.org/work_packages/73756

What are you trying to accomplish?

Make WorkPackage.find and .exists? transparently resolve semantic identifiers (e.g. "PROJ-42") in addition to numeric IDs. Also widen Rails route constraints to accept semantic IDs, and update controller/ViewComponent finders to use find_by_id_or_identifier.

This is the second part of the API layer work — PR #22710 introduced the displayId field, and this PR makes the routes and finders work end-to-end with semantic identifiers.

Screenshot 2026-04-14 at 11 45 45 AM

What approach did you choose and why?

Extracted a FinderMethods module in WorkPackage::SemanticIdentifier that is shared between the class-level WorkPackage methods and ActiveRecord relation extensions (via super.extending(FinderMethods)). This ensures scoped queries like WorkPackage.visible(user).find("PROJ-42") work correctly.

The dispatch uses a semantic_id? predicate — it strips whitespace, rejects non-strings and numeric strings, and returns true only for identifiers like "PROJ-42". Numeric lookups fall through to standard ActiveRecord find.

The exists? override mirrors the same resolution chain: check the identifier column, then fall back to the work_package_semantic_aliases table for historical identifiers.

Also extracts ID_ROUTE_CONSTRAINT into WorkPackage::SemanticIdentifier so the regex for matching work package identifiers in URLs is defined once and referenced from both route definitions in config/routes.rb.

Merge checklist

  • Added/updated tests
  • Added/updated documentation in Lookbook (patterns, previews, etc)
  • Tested major browsers (Chrome, Firefox, Edge, ...)

@akabiru akabiru self-assigned this Apr 10, 2026
@akabiru akabiru marked this pull request as draft April 10, 2026 15:26
@akabiru akabiru force-pushed the feature/73735-expose-project-based-semantic-work-package-identifier-on-the-api branch from 2a99fe8 to 2839dc2 Compare April 10, 2026 15:37
@akabiru akabiru force-pushed the feature/73756-adapt-routes-for-project-based-semantic-work-package-identifiers branch from 7c38287 to a3b5e32 Compare April 10, 2026 15:37
@akabiru akabiru force-pushed the feature/73735-expose-project-based-semantic-work-package-identifier-on-the-api branch from 2839dc2 to 47c4b8a Compare April 10, 2026 15:47
@akabiru akabiru force-pushed the feature/73756-adapt-routes-for-project-based-semantic-work-package-identifiers branch 2 times, most recently from bb04400 to c466ac6 Compare April 10, 2026 16:04
@akabiru akabiru force-pushed the feature/73735-expose-project-based-semantic-work-package-identifier-on-the-api branch from 47c4b8a to 5bbc4e7 Compare April 13, 2026 11:04
@akabiru akabiru force-pushed the feature/73756-adapt-routes-for-project-based-semantic-work-package-identifiers branch from 128f33b to be79dc3 Compare April 13, 2026 11:05
@id = id
@tab = tab
@work_package = WorkPackage.visible.find_by(id:)
@work_package = WorkPackage.visible.find_by_id_or_identifier(id)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick one: Don't we already want to call a simple find here? Same for the other occurrences.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we were using find_by(id:) before- I suppose we don't want RecordNotFound errors that would be raised by find?

@akabiru akabiru marked this pull request as ready for review April 14, 2026 08:45
@akabiru akabiru requested review from a team, judithroth and thykel April 14, 2026 08:46
Base automatically changed from feature/73735-expose-project-based-semantic-work-package-identifier-on-the-api to dev April 14, 2026 14:17
akabiru added 8 commits April 14, 2026 17:38
Extract FinderMethods module that transparently resolves both numeric and
semantic identifiers (e.g. "PROJ-42") using FriendlyId's Object#friendly_id?
for dispatch. The module is included in both the WorkPackage class and
extended onto every relation, so scoped queries like
WorkPackage.visible(user).find("PROJ-42") work seamlessly.

- Override find to resolve semantic IDs via identifier column + alias table
- Override exists? with the same resolution chain
- Refactor find_by_id_or_identifier to use friendly_id? instead of semantic_id?
- Update API route to accept string IDs (type: Integer → type: String)
- Update controller and ViewComponent finders to use find_by_id_or_identifier
- Pass display_id from Rails views to Angular custom elements
Replace FriendlyId's Object#friendly_id? monkey-patch with a private
semantic_id? method that owns the full dispatch decision: type check,
whitespace stripping, and numeric detection in one place.

This fixes a bug where numeric strings with whitespace (e.g. " 456 "
from comma-split input) were misclassified as semantic identifiers
because " 456".to_i.to_s != " 456".
Replace stubbed work package and mock permission chain with real
database records and role membership. This eliminates rubocop violations
(ExpectInHook, StubbedMock, MessageChain) while also testing the actual
finder path through WorkPackage.visible.
The route constraint for work_packages#show used /\d+/ which rejected
semantic identifiers like "KSTP-7". Widen to also match the
PROJECTID-SEQ pattern so both numeric and semantic IDs route correctly.
Verifies that GET /work_packages/PROJ-42 routes to work_packages#show,
matching the widened route constraint.
Centralise the regex that matches both numeric IDs and semantic
identifiers into a named constant so route definitions reference
a single source of truth instead of duplicating the pattern.
Pass model, primary_key, and id to ActiveRecord::RecordNotFound so
error reporters and rescue handlers get the same structured data
that Rails' own find provides.
"eeek" now matches the semantic identifier pattern, so
find_by_id_or_identifier! raises RecordNotFound with
model: "WorkPackage", producing the WP-specific error
message instead of the generic 404.
@akabiru akabiru force-pushed the feature/73756-adapt-routes-for-project-based-semantic-work-package-identifiers branch from 73bae1e to 48946fe Compare April 14, 2026 15:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants