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_name under 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

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 Screenshot_2026-09-23_at_21.13.23
After Screenshot_2026-09-23_at_21.12.16

How to set up and validate locally

  1. Create a group with a group-level milestone, for example titled test.
  2. Visit https://gdk.test:3443/search?group_id=<group id>&scope=milestones&search=test.
  3. Before this fix, the page errors out.
  4. 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 on source_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.

🤖 Generated with Claude Code

Edited by Ravi Kumar

Merge request reports

Loading
Loading