Change the shape of ActiveRecord::Migration::CommandRecorder#commands
From uloza+hey@proton.me · original ↗ · unsubscribe
Each recorded migration command is now stored as [cmd, args, kwargs, block] (4-element) instead of [cmd, args, block] (3-element) with kwargs bundled into a trailing hash inside args. Code that inspects recorder.commands directly needs to adapt to the new tuple shape.
Refactor `CommandRecorder` to store args and kwargs separately by kamipo · Pull Request #58239 · rails/rails · GitHub
Navigation Menu
Appearance settings
-
Platform
-
AI CODE CREATION
-
DEVELOPER WORKFLOWS
-
APPLICATION SECURITY
-
EXPLORE
-
-
Solutions
-
BY COMPANY SIZE
-
BY USE CASE
-
BY INDUSTRY
-
-
Resources
-
EXPLORE BY TOPIC
-
EXPLORE BY TYPE
-
SUPPORT & SERVICES
-
-
Open Source
-
COMMUNITY
-
PROGRAMS
-
REPOSITORIES
-
-
Enterprise
Search/
Appearance settings
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session. Dismiss alert
Uh oh!
There was an error while loading. Please reload this page.
- Notifications You must be signed in to change notification settings
- Fork 22.4k
- Code
- Issues 485
- Pull requests 1.1k
- Discussions
- Actions
- Security and quality 26
- Insights
Additional navigation options
Refactor CommandRecorder to store args and kwargs separately - #58239
#58239
Merged
kamipo merged 1 commit into
mainrails/rails:mainfrom
refactor-command-recorder-kwargsrails/rails:refactor-command-recorder-kwargsCopy head branch name to clipboard
Aug 9, 2026
ConversationCommits1 (1)ChecksFiles changed
Merged
##
Refactor CommandRecorder to store args and kwargs separately#58239
kamipo merged 1 commit into
mainrails/rails:mainfrom
refactor-command-recorder-kwargsrails/rails:refactor-command-recorder-kwargsCopy head branch name to clipboard
Conversation
###
kamipo commented Jul 25, 2026 •
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
Copy link
Copy Markdown
Member
recorder.commands now stores each recorded migration command as [cmd, args, kwargs, block] (4-element) instead of [cmd, args, block] (3-element) with kwargs bundled into a trailing hash inside args. Code that inspects recorder.commands directly needs to adapt to the new tuple shape.
The old encoding was inherited from the ruby2_keywords transition period, where kwargs and positional args had to travel through a single flat array with the trailing hash marked as kwargs. Since Rails now requires Ruby 3.3.1+ (where kwargs are properly separated), the shim is no longer needed. All invert_* helpers now receive args and kwargs separately — removing the .extract_options!, .last.is_a?(Hash), and args << options patterns that the ruby2_keywords idiom required.
This direction is aligned with a Ruby proposal to deprecate ruby2_keywords in the future (https://bugs.ruby-lang.org/issues/22205), since libraries that only support Ruby 3.0+ no longer need it.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
❤️ 1 skipkayhil reacted with heart emoji
All reactions
- ❤️ 1 reaction
github-actions Bot added the activerecord label Jul 25, 2026
Base automatically changed from remove-ruby2-keywords to main July 26, 2026 05:20
kamipo force-pushed the refactor-command-recorder-kwargs branch from f0b9d6a to a978233 Compare July 26, 2026 06:02
kamipo mentioned this pull request Jul 26, 2026
Make CommandRecorder#record and #inverse_of private #58254
Merged
kamipo added a commit to kamipo/rails that referenced this pull request Aug 2, 2026
[Make `CommandRecorder#record` and `#inverse_of` private](/kamipo/rails/commit/560645a8c270d583b516031506081834583ae339 "Make `CommandRecorder#record` and `#inverse_of` private #58238 removed `ruby2_keywords` method calls, but places that store method arguments for later invocation (`CommandRecorder`, ActiveJob, etc.) still rely on `Hash.ruby2_keywords_hash` to fold kwargs into args as a trailing flagged hash. `Hash.ruby2_keywords_hash` is also planned to be deprecated, so we need to migrate to a structure that stores positional args and keyword args separately instead of depending on a flagged trailing hash. That structural change breaks the signatures of `CommandRecorder#record` and `#inverse_of`. Normally, Rails goes through a deprecation cycle when changing public API. But `record` and `inverse_of` are internal machinery — `CommandRecorder` is meant to behave like a connection wrapper that records migration commands (`create_table`, `add_column`, etc.) instead of executing them, and `record`/`inverse_of` are not part of that surface. Based on how they are used, they should not be called directly. They are still exposed as public API in the docs (https://api.rubyonrails.org/classes/ActiveRecord/Migration/CommandRecorder.html), which I noticed while working on #58239. Rather than treating the upcoming signature change (#58239) as an incompatible public-API change in its CHANGELOG entry, make these methods private up front. Making public methods private without a deprecation cycle is normally undesirable, but `CommandRecorder` is an internal component rather than an end-user API, so this incompatibility should be acceptable.") …
[560645a](/kamipo/rails/commit/560645a8c270d583b516031506081834583ae339)
rails#58238 removed `ruby2_keywords` method calls, but places that store method arguments for later invocation (`CommandRecorder`, ActiveJob, etc.) still rely on `Hash.ruby2_keywords_hash` to fold kwargs into args as a trailing flagged hash. `Hash.ruby2_keywords_hash` is also planned to be deprecated, so we need to migrate to a structure that stores positional args and keyword args separately instead of depending on a flagged trailing hash. That structural change breaks the signatures of `CommandRecorder#record` and `#inverse_of`.
Normally, Rails goes through a deprecation cycle when changing public API. But `record` and `inverse_of` are internal machinery — `CommandRecorder` is meant to behave like a connection wrapper that records migration commands (`create_table`, `add_column`, etc.) instead of executing them, and `record`/`inverse_of` are not part of that surface. Based on how they are used, they should not be called directly. They are still exposed as public API in the docs (https://api.rubyonrails.org/classes/ActiveRecord/Migration/CommandRecorder.html), which I noticed while working on rails#58239.
Rather than treating the upcoming signature change (rails#58239) as an incompatible public-API change in its CHANGELOG entry, make these methods private up front. Making public methods private without a deprecation cycle is normally undesirable, but `CommandRecorder` is an internal component rather than an end-user API, so this incompatibility should be acceptable.
kamipo force-pushed the refactor-command-recorder-kwargs branch 2 times, most recently from e0625bf to 3164b44 Compare August 2, 2026 17:22
[Refactor `CommandRecorder` to store args and kwargs separately](/rails/rails/pull/58239/commits/3efea4e0618e7316ac4da5c217c2fd92b64954be "Refactor `CommandRecorder` to store args and kwargs separately `recorder.commands` now stores each recorded migration command as `[cmd, args, kwargs, block]` (4-element) instead of `[cmd, args, block]` (3-element) with kwargs bundled into a trailing hash inside `args`. Code that inspects `recorder.commands` directly needs to adapt to the new tuple shape. The old encoding was inherited from the `ruby2_keywords` transition period, where kwargs and positional args had to travel through a single flat array with the trailing hash marked as kwargs. Since Rails now requires Ruby 3.3.1+ (where kwargs are properly separated), the shim is no longer needed. All `invert_*` helpers now receive args and kwargs separately — removing the `.extract_options!`, `.last.is_a?(Hash)`, and `args << options` patterns that the `ruby2_keywords` idiom required. This direction is aligned with a Ruby proposal to deprecate `ruby2_keywords` in the future (https://bugs.ruby-lang.org/issues/22205), since libraries that only support Ruby 3.0+ no longer need it.") …
[3efea4e](/rails/rails/pull/58239/commits/3efea4e0618e7316ac4da5c217c2fd92b64954be)
`recorder.commands` now stores each recorded migration command as `[cmd, args, kwargs, block]` (4-element) instead of `[cmd, args, block]` (3-element) with kwargs bundled into a trailing hash inside `args`. Code that inspects `recorder.commands` directly needs to adapt to the new tuple shape.
The old encoding was inherited from the `ruby2_keywords` transition period, where kwargs and positional args had to travel through a single flat array with the trailing hash marked as kwargs. Since Rails now requires Ruby 3.3.1+ (where kwargs are properly separated), the shim is no longer needed. All `invert_*` helpers now receive args and kwargs separately — removing the `.extract_options!`, `.last.is_a?(Hash)`, and `args « options` patterns that the `ruby2_keywords` idiom required.
This direction is aligned with a Ruby proposal to deprecate `ruby2_keywords` in the future (https://bugs.ruby-lang.org/issues/22205), since libraries that only support Ruby 3.0+ no longer need it.
kamipo force-pushed the refactor-command-recorder-kwargs branch from 3164b44 to 3efea4e Compare August 8, 2026 10:23
kamipo mentioned this pull request Aug 8, 2026
Refactor MiddlewareStack::Middleware off Hash.ruby2_keywords_hash #58420
Merged
Hide details View details
kamipo merged commit 342dafc into main Aug 9, 2026
7 checks passed
Uh oh!
There was an error while loading. Please reload this page.
kamipo deleted the refactor-command-recorder-kwargs branch August 9, 2026 08:10
kamipo added a commit that referenced this pull request Aug 9, 2026
[Refactor `MiddlewareStack::Middleware` off `Hash.ruby2_keywords_hash`](/rails/rails/commit/26b88332672781769fec3279d9c504f5ee9fffde "Refactor `MiddlewareStack::Middleware` off `Hash.ruby2_keywords_hash` Follow-up to #58239. `Hash.ruby2_keywords_hash` is scheduled for deprecation (https://bugs.ruby-lang.org/issues/22205); libraries that only support Ruby 3.0+ shouldn't depend on it. `Middleware` (and its `ActionController` subclass) now store positional args and keyword args separately (`@args` / `@kwargs`) instead of bundling `Hash.ruby2_keywords_hash(kwargs)` into `@args`, and `#build` dispatches with `klass.new(app, *args, **kwargs, &block)`. `Middleware` and `InstrumentationProxy` are also marked `:nodoc:`. Users interact with the stack through `use` / `insert` / etc. and, for instrumentation, subscribe to `process_middleware.action_dispatch` (documented in the Active Support Instrumentation guide). Neither class is intended to be constructed directly, so their internal structure doesn't belong in the API docs even though iterating `Rails.application.middleware` still exposes `Middleware#args` / `#kwargs` for debugging.") …
[26b8833](/rails/rails/commit/26b88332672781769fec3279d9c504f5ee9fffde)
Follow-up to #58239. `Hash.ruby2_keywords_hash` is scheduled for deprecation (https://bugs.ruby-lang.org/issues/22205); libraries that only support Ruby 3.0+ shouldn’t depend on it.
`Middleware` (and its `ActionController` subclass) now store positional args and keyword args separately (`@args` / `@kwargs`) instead of bundling `Hash.ruby2_keywords_hash(kwargs)` into `@args`, and `#build` dispatches with `klass.new(app, *args, **kwargs, &block)`.
`Middleware` and `InstrumentationProxy` are also marked `:nodoc:`. Users interact with the stack through `use` / `insert` / etc. and, for instrumentation, subscribe to `process_middleware.action_dispatch` (documented in the Active Support Instrumentation guide). Neither class is intended to be constructed directly, so their internal structure doesn’t belong in the API docs even though iterating `Rails.application.middleware` still exposes `Middleware#args` / `#kwargs` for debugging.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
### Reviewers
No reviews
Assignees
No one assigned
Labels
Projects
None yet
Milestone
No milestone
Development
Successfully merging this pull request may close these issues.
Uh oh!
There was an error while loading. Please reload this page.
1 participant
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Footer
Footer navigation
- Terms
- Privacy
- Security
- Status
- Community
- Docs
- Contact
- Manage cookies
- Do not share my personal information
You can’t perform that action at this time.