Fix group milestone results in milestone search
What does this MR do and why?
Group search results for milestones crash the page. Visiting the milestones tab of group search raises ActionController::UrlGenerationError whenever a group-level milestone is in the results. Group milestone results are also missing the parent name that project milestones show under the title.
This started when group and project basic search were changed to include group-level milestones. The search result partial app/views/search/results/_milestone.html.haml still builds every milestone link with project_milestone_path(milestone.project, milestone). A group milestone has no project, so milestone.project is nil and the route can't be built.
The fix:
- Use the existing
milestone_path(milestone)direct route instead. It picks the group or project path depending on the milestone type, so both group and project milestones link correctly. - Show
milestone.resource_parent.full_nameunder every result, so group milestones show the group name, the same way project milestones show the project name. - Preload the group's route in
Milestone.with_web_entity_associations, which the search page already uses for milestones, so rendering group milestone links and names doesn't run a query per result.
References
- https://gitlab.com/gitlab-org/gitlab/-/issues/589711 — the change that made group and project search return group-level milestones, which exposed this bug.
Screenshots or screen recordings
No screenshots attached. The "before" state is a 500 error page, not a rendered view, so a screenshot doesn't add much.
| State | What you'd see |
|---|---|
| Before | ![]() |
| After | ![]() |
How to set up and validate locally
- Create a group with a group-level milestone, for example titled
test. - Visit
https://gdk.test:3443/search?group_id=<group id>&scope=milestones&search=test. - Before this fix, the page errors out.
- After this fix, the group milestone is listed, links to
/groups/<group>/-/milestones/<iid>, and shows the group name under the title.
spec/views/search/_results.html.haml_spec.rb gets a group milestone example that checks the result links to the group milestone and shows the group name. It fails with the same UrlGenerationError without the fix. The existing milestone examples in that file already render a project milestone result.
spec/lib/gitlab/group_search_results_spec.rb gets an example that checks the group and its route are preloaded.
Database
The milestone search query itself is unchanged (it's from !223162 (merged)). This MR adds one batched preload query to fetch the routes for groups on the current page.
SELECT "routes".* FROM "routes" WHERE "routes"."source_type" = 'Namespace' AND "routes"."source_id" IN (<group ids of milestones on the page>)- Runs once per page, and the id list is bounded by the page size.
- Uses the unique index
index_routes_on_source_type_and_source_id(btree onsource_type,source_id). - Replaces the per-row lookup that ran once for each group milestone result.
Query plan: https://console.postgres.ai/shared/96f8c2f2-41fe-4bc4-b327-7f1ed5edca1a
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

