Skip to content

actionpack: type the routing Mapper DSL - #1106

Open
apiology wants to merge 5 commits into
ruby:mainfrom
apiology:actionpack-type-resources-new
Open

apiology wants to merge 5 commits into
ruby:mainfrom
apiology:actionpack-type-resources-new

Conversation

@apiology

@apiology apiology commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Claude: This PR was written by Claude Code on behalf of @apiology.

Problem:

Route files type-check against untyped, so routing mistakes pass:

Rails.application.routes.draw do
  # no error, though Rails rejects a Symbol `to:` when it loads the routes
  get "recent", to: :recent
  resources :photos do
    # untyped, though Rails returns the block value
    new { 1 }.succ
  end
end

This covers the public ActionDispatch::Routing::Mapper DSL in 7.2 and 8.1.

Solution: Declare the DSL in actiondispatch.rbs from mapper.rb (v7.2.4, v8.1.4), moving each generated declaration's Rails documentation with it:

  • Aliases and interfaces in Mapper name what Mapping, Resource and Scope accept: paths, via, format, only/except, to (strings, Rack apps, lambdas, controller classes), constraints (hashes, matches? objects, request lambdas) and on.
  • Overloads cover the "path" => "controller#action" and App => "path" hash forms, and concern with a lambda, callable or block. The verbs, match and mount drop the block, which Rails never calls.
  • Returns: the mapper for resources, scope and the verbs; the block value for collection, member, new, shallow, controller and defaults; in 8.1, the path array for match and root, which end in path_or_actions.each.

mount keeps an untyped app, since engine classes respond to call only through railties. 6.0 is unchanged, per gems/actionpack/README.md.

apiology and others added 5 commits October 19, 2026 12:48
In Rails 6.0 through 8.1, Mapper::Resources#new yields through
with_scope_level and path_scope, each of which returns the block's
value. Replace the generated untyped signature with a generic one in
actiondispatch.rbs, and test it in the 7.2 and 8.1 suites.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SEntZKsZwQHhzqcwG7MTqn
gems/actionpack/README.md accepts changes only for Rails versions
under maintenance, and 6.0 is not one, so restore its RBS.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SEntZKsZwQHhzqcwG7MTqn
In Rails 7.2 and 8.1 the Mapper DSL methods either return the mapper
(resource, resources, nested, namespace, scope, constraints, the HTTP
verb helpers, mount, with_default_scope, and match/root in 7.2) or the
value of their block (collection, member, shallow, controller,
defaults), because they end in `self` or in `yield` through
with_scope_level, path_scope and shallow_scope. The generated
signatures returned untyped and required blocks on match (7.2) and
concern, which also accepts a callable.

In 8.1, Resources#match returns its path_or_actions array (it ends in
`path_or_actions.each`), and root returns match's value, so both are
typed as Array. Concerns#concerns likewise ends in `each`.

Move these declarations out of actionpack-generated.rbs into
actiondispatch.rbs, add the missing 7.2 HttpHelpers#options, and cover
them in the 7.2 and 8.1 route-drawing tests.

Sources: actionpack/lib/action_dispatch/routing/mapper.rb at v7.2.4
and v8.1.4.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SEntZKsZwQHhzqcwG7MTqn
The previous commit dropped the Rails doc comments of the declarations
it moved out of actionpack-generated.rbs and typed only return values.
Move each doc comment onto its hand-written declaration, and type the
arguments, options and blocks from mapper.rb at v7.2.4 and v8.1.4:

- Type aliases and interfaces in Mapper name the option values that
  Mapping, Resource and Scope accept: paths, `via`, `format`,
  `only`/`except`, `to` endpoints (strings, Rack apps and lambdas,
  controller classes), constraints (hashes, `matches?` objects and
  request lambdas), and `on`.
- `get`..`connect`, `match` and `mount` gain an overload for the
  `"path" => "controller#action"` and `App => "path"` hash forms, and
  drop the block Rails never calls.
- `concern` gets overloads for a lambda, a callable object, or a block
  run on the mapper.
- 8.1 also moves mount, options and connect out of the generated file.

In 7.2 the verbs and match take several paths and match/root return
the mapper; in 8.1 they take one path and match/root return the path
array.

The tests draw routes in the forms the Rails routing guide uses.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SEntZKsZwQHhzqcwG7MTqn
concern with a block stores and returns the same mapper lambda shape
as concern with a lambda, so type both overloads alike.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SEntZKsZwQHhzqcwG7MTqn
@apiology apiology changed the title actionpack: type the routing Mapper DSL return values actionpack: type the routing Mapper DSL Oct 19, 2026
@apiology
apiology marked this pull request as ready for review October 19, 2026 18:31
@github-actions

Copy link
Copy Markdown

@apiology Thanks for your contribution!

Please follow the instructions below for each change.
See also: https://github.com/ruby/gem_rbs_collection/blob/main/docs/CONTRIBUTING.md

Available commands

You can use the following commands by commenting on this PR.

  • /merge: Merge this PR if CI passes

actionpack

You changed RBS files for an existing gem.
You need to get approval from the reviewers of this gem.

@ksss, @tk0miya, please review this pull request.
If this change is acceptable, please make a review comment including APPROVE from here.
Screen Shot 2024-03-19 at 14 13 36

After that, the PR author or the reviewers can merge this PR.
Just comment /merge to merge this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant