Skip to content

Rails 4.0 patterns: routing entries (duplicate roots, controller names, route-file modules)#103

Open
JuanVqz wants to merge 3 commits into
mainfrom
feature/rails-40-patterns-pr2
Open

Rails 4.0 patterns: routing entries (duplicate roots, controller names, route-file modules)#103
JuanVqz wants to merge 3 commits into
mainfrom
feature/rails-40-patterns-pr2

Conversation

@JuanVqz

@JuanVqz JuanVqz commented May 26, 2026

Copy link
Copy Markdown
Member

Summary

Three new Rails 4.0 routing patterns that boot-fail or break callers, currently undetected by the OSS skill.

  • DUPLICATE_ROOT_ROUTES — Rails 4 raises ArgumentError: Invalid route name, already in use: 'root' on the second root declaration. The naive fix (give each duplicate an as:) silently breaks every root_path / root_url caller; fix keeps the FIRST as default :root and renames only the rest. Includes a grep verification step.
  • ROUTES_CONTROLLER_NAMES — Rails 4 raises ArgumentError: 'foo-bar' is not a supported controller name for hyphenated or CamelCase to: values. URL paths are unaffected. snake_case rewrite is backwards-compatible on 3.2.
  • ROUTES_TOP_LEVEL_MODULE_AUTOLOAD — Rails 4's route loader doesn't persist top-level module definitions across the reload boundary; references to those constants raise NameError on reload. Two-part fix branched on NextRails.next? (move classes to convention paths + add config.autoload_paths).

All three classified high_priority / kind: breaking. Boot-fatal on Rails 4.

Test plan

  • bin/validate-patterns rails-upgrade/detection-scripts/patterns/rails-40-patterns.yml clean.
  • Reviewer spot-checks the three regexes against representative route files.

@JuanVqz JuanVqz requested a review from etagwerker May 26, 2026 00:06
@JuanVqz JuanVqz self-assigned this May 26, 2026
JuanVqz added 3 commits July 3, 2026 20:39
Rails 4 raises ArgumentError: Invalid route name, already in use:
'root' when the routes file has more than one `root` declaration
(typically one per constraint block). Rails 3.2 was lenient about
duplicate names with different constraints, so this slips through on
many 3.x codebases.

The naive fix — give each duplicate an `as:` — silently breaks every
root_path / root_url caller in the codebase because the :root name
is no longer registered to any declaration. Real apps have dozens to
hundreds of these helper calls in controllers, views, mailers, and
tests.

Correct fix: keep the FIRST declaration as the default :root, only
add `as:` to the SECOND and subsequent. Includes a grep verification
step so operators confirm no caller targets a constraint-bound root
that was renamed.

Classified high_priority / kind: breaking — Rails 4 boot raises
outright on the duplicate.
Rails 4 validates controller names in `to:` clauses with strict
rules: no hyphens, no CamelCase. Hyphenated values raise
ArgumentError: 'foo-bar' is not a supported controller name; the
CamelCase form raises the same error. Rails 3.2 was lenient and
auto-normalized.

Common shapes that trigger the regex:

  get "/", to: "my-pages#show"      # hyphen
  get "/", to: "MyPages#show"       # CamelCase

URL paths (the route path itself) can keep hyphens — only the
controller class reference in `to:` needs to be snake_case. The fix
field calls this out so operators don't accidentally rewrite path
strings.

The snake_case form resolves to the same controller class on Rails
3.2, so the rewrite ships pre-bump and is backwards-compatible.

Classified high_priority / kind: breaking — Rails 4 boot raises on
the bad name.
Rails 4's route loader does not reliably persist top-level module
definitions across the routes-reload boundary. A pattern like

  module Constraints
    class Admin
      ...
    end
  end

defined inside a config/routes/*.rb file may evaluate at boot but
the Constraints constant does not survive subsequent reloads, and
downstream uses like `constraints Constraints::Admin do ... end`
raise NameError: uninitialized constant Constraints. Rails 3.2
handled this more leniently — modules defined in route files
persisted across reload boundaries.

Fix is two-part, branched on NextRails.next?:

1. Move the module's class definitions to convention paths
   (e.g. config/routes/constraints/admin.rb for Constraints::Admin)
   so Rails autoload finds them.

2. Add the parent directory to config.autoload_paths, also gated by
   NextRails.next?, so the new layout only applies on the Rails 4+
   side. Rails 3.2 still wants the modules at the original path
   inside the route file.

The exclude regex skips RSpec:: and Constraints:: references that
match the leading `module` pattern but are not actual module
definitions.

Classified high_priority / kind: breaking — Rails 4 raises NameError
on the first reload that hits the dropped constant.
@etagwerker etagwerker force-pushed the feature/rails-40-patterns-pr2 branch from 1a0aaa9 to 0a1c21e Compare July 4, 2026 00:39
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.

1 participant