Ruby on Rails — Aug 2025
All the Rails News That Matters, Once a Month!

Ruby on Rails — Aug 2025


Hey everyone — Sajjad Umar here with the August edition of Ruby on Rails Monthly!

A quick personal note before we dive in: I had to skip the July 2025 issue. Between a packed schedule and my 3.5-year-old daughter taking a fall down the stairs and breaking her arm, things got a little overwhelming. She’s doing much better now, thankfully. Thanks for bearing with me — this edition makes up for the gap by digging deeper into the biggest changes since mid-June.

Our Proud Partners

Let's dive in!

Rails Foundation

New written & video tutorials for beginners

The Rails Foundation, in collaboration with Chris Oliver and the Typecraft team, has rolled out several learning resources for newcomers — both written and video.

They’ve launched a new written tutorial, “Sign Up & Settings,” which builds on the updated Getting Started guide. It teaches you how to set up admin accounts, allow user registrations, manage nested layouts, add rate limiting, and write tests for different user roles. This continues the e-commerce app series started last year.

For visual learners, there’s now a video series called “Rails New” by Typecraft. Across 10 beginner-friendly episodes, you’ll go from installation through rails new, scaffolding, MVC fundamentals, styling with TailwindCSS, and even deploying with Kamal.

These additions reflect the Education mission of the Rails Foundation — and are a great boost for anyone learning Rails from scratch.

Check the full playlist here.

Structured Event Reporting lands in Rails!

Rails now offers a dedicated Event Reporter, available through Rails.event, designed for producing richly structured events—spanning structured logs, telemetry, and business events—all via a unified interface.

When emitting events, Rails now automatically augments them with consistent metadata:

  • Name of the event
  • Payload — with arbitrary data or schematized object
  • Tags — domain-specific, stackable metadata
  • Context — request/job-scoped information, e.g., request_id, user_agent
  • Timestamp at nanosecond precision
  • Source location — file path, line number, and label

Rails adds tools to streamline event enrichment:

  • Rails.event.tagged(...) { ... } — wraps events in nested tags
  • Rails.event.set_context(...) — sets contextual metadata for the entire request/job scope

Through Rails.event.with_debug, developers can conditionally emit debug-level events:

Rails.event.with_debug do
  Rails.event.debug("sql_query", { sql: "SELECT * ..." })
end        

These events are emitted only if debug mode is active.

Emission is decoupled from consumption:

  • Developers define subscribers implementing an emit(event) method.
  • These subscribers receive the complete structured event and decide how to handle it — e.g., serialize, forward, or log.
  • The framework doesn’t bake in any default consumers, giving flexibility to applications to define processing pipelines

Rails now supports test assertions to verify event emissions:

assert_event_reported("user.created", payload: { id: 123 }) do
  UserService.create_user(name: "John")
end

assert_no_event_reported("user.deleted") do
  UserService.update_user(...)
end        

These make it easier to validate expected event behaviors in your app’s test suite.

What This Means for Rails Developers

Observability and analytics: Rails now ships with a first-class event reporting system, enabling structured data capture for logs, metrics, or business signals.

Greater flexibility: With subscriber-driven architecture, apps can define how events are processed — whether that means JSON serialization, external services, or custom pipelines.

Improved testing: Event assertions allow reliable testing of telemetry and business event behaviors.

Optional layering: Rails doesn’t force this system onto all apps; developers can adopt it gradually, integrating as needed.

Learn more about it here.

assert_events_reported Test Helper

Rails PR #55497 adds the assert_events_reported helper for testing event-driven behavior. It lets you assert that certain events were emitted during a block, without caring about order or extra events.

Example:

assert_events_reported("event-x", "event-z") do
  CheckoutService.run_checkout
endru        

You can even check payloads:

assert_events_reported(["user.created", { id: 123 }]) do
  UserService.create_user(id: 123, name: "John")
end        

This makes it much easier to test logging, telemetry, background jobs, and business events — focusing on intent rather than sequence.

deliver_all_later for Bulk Enqueuing Emails

In PR #55448, Rails introduces a handy new method — ActionMailer.deliver_all_later—that lets you enqueue multiple emails in one go, drastically cutting down on queue round-trips.

A quick code peek:

user_emails = User.all.map { |user| Notifier.welcome(user) }
ActionMailer.deliver_all_later(user_emails)

# Or enqueue with a custom queue:
ActionMailer.deliver_all_later(user_emails, queue: :my_queue)        

I’ve been needing this exact feature — imagine sending thousands of welcome emails efficiently without looping one by one. This method batches them all into a single call, making your mailer pipeline leaner and faster.

What’s cool is how naturally it fits into Rails. It builds on an existing concept — similar to what we’ve seen with bulk actions elsewhere — and now it applies it to email delivery specifically.

Add “Copy as Text” Button to Error Pages

In PR #55431, Rails added a neat little UX feature: a “Copy as Text” button on error pages. As a developer, I love this. Often when debugging, I find myself copying error messages manually — whether to Google them, share with teammates, or even paste into an AI assistant. This button does that in one click.

The button gets added to the error page header and grabs a plain-text version of the error (reusing the already formatted log output, which is concise and helpful) onto your clipboard — no manual selection needed.

Article content

Removing autocomplete="off" from Hidden Inputs in button_to

In PR #55336, Rails cleaned up HTML by removing the unnecessary autocomplete="off" attribute from hidden inputs generated by methods like button_to, token_tag, and method_tag. This attribute was redundant and resulted in invalid markup. GitHub

The change simplifies the generated form helpers without altering behavior — other than cleaner HTML. Tests were updated accordingly to reflect this removal.

Composite Model Channels for ActionCable stream_for

In this PR, Rails enhances ActionCable::Channel#stream_for to accept multiple model objects—just like Turbo::Broadcastable#broadcasting_to. Clauses like the following are now supported:

class BroadcastSignalChannel < ApplicationCable::Channel
  def subscribed
    return reject unless set_account_broadcast

    stream_for [@account_broadcast, current_user]
  end
  # ...
end        

This adjustment means you can effortlessly stream to a combination of targets — think model and its owner — without manually wiring up multiple streams. It’s especially useful when you’re doing more than just rendering HTML, such as powering WebRTC signaling over ActionCable.

Shared Rate Limits Across Controllers

Rails now lets you define shared rate limits across multiple controllers using a new scope option—great when you want to rate-limit groups of endpoints together (like all API routes), instead of per-controller by default.

Here’s how it works: instead of this:

class API::PostsController < ApplicationController
  rate_limit to: 100, within: 1.minute
end

class API::UsersController < ApplicationController
  rate_limit to: 100, within: 1.minute
end        

…where each controller gets its own counter, you can now do this:

class APIController < ActionController::API
  rate_limit to: 100, within: 1.minute, scope: :api_global
end

class API::PostsController < APIController
  # inherits same scoped limit
end

class API::UsersController < APIController
  # shares limit with others under :api_global
end        

This means API::PostsController and API::UsersController share the same rate limit counter, enforcing a global cap across both. The implementation adjusts the cache key generation to use scope instead of the default controller_path when provided or falling back to it when not.

Support for rack.response_finished Callbacks in ActionDispatch::Executor

This PR includes support for Rack’s rack.response_finished callbacks in ActionDispatch::Executor, allowing Rails apps to defer certain “completion” operations until after the full response lifecycle—ideal for cleanup or logging logic that runs too early otherwise.

In simpler terms: Previously, Rails’ executor middleware ran “ensure”-style callbacks immediately when the controller action finished. Now, if your server implements rack.response_finishedThose callbacks can wait until the response is fully sent—so they run at just the right moment, not before your app’s cleanup logic has had a chance to wrap up.

Configurable Render Tracker in Action View

Rails now makes its render tracker configurable, giving developers the option to choose between different parser-based implementations. Previously, Rails experimented with a Ripper-based tracker but rolled it back. With the Prism parser now becoming the default in Rails 7.2, this change introduces a cleaner, more reliable approach for detecting render calls.

New Rails 8.1 apps will default to the Ruby-parser-based tracker, while existing apps can switch rendering strategies through a simple configuration setting. These new trackers not only improve accuracy but also simplify maintenance, especially in tricky cases like trailing interpolation.

You can check out the full discussion and implementation details in the PR here.

credentials:fetch Command Added to Rails Credentials API

Rails now provides a new command, rails credentials:fetch, making it easier to extract specific secrets directly from your encrypted credentials. Previously, accessing a credential meant using rails credentials:edit or show, which required manual extraction or parsing. Now, you can retrieve a credential's raw value—ideal for scripting or populating environment variables.

For example:

RAILS_MASTER_KEY=... so my script can decrypt...
KAMAL_REGISTRY_PASSWORD=$(rails credentials:fetch kamal/registry_password)        

This handy addition is particularly useful in automation and deployment scenarios — for instance, injecting secrets into tools like Kamal or CI pipelines.

You can explore the full discussion and implementation in the pull request itself.

Making ActiveSupport::Logger #freeze-Friendly

Rails introduced a subtle but practical change in PR 55465 that smooths out behavior when loggers are frozen.

Previously, calling methods like logger.level or logger.debug on a frozen ActiveSupport::Logger could raise a FrozenError. This PR fixes that by ensuring the internal @local_level_key instance variable is initialized eagerly—meaning the logger can operate normally even after being frozen.

A quick code example from the change:

def local_level_key
  @local_level_key ||= :"logger_thread_safe_level_#{object_id}"
end
attr_reader :local_level_key        

And the added test that confirms the fix works without crashing:

logger.freeze
assert_nothing_raised do
  assert_equal Logger::DEBUG, logger.level
end        

To sum it up: this is a neat quality-of-life improvement that avoids unnecessary errors in frozen-logger scenarios — keeping things stable, predictable, and developer-friendly.

ERB::Util.html_escape: Stop “Tidying” Bytes for Better Performance

PR 55467 improves the ERB::Util.html_escape method by removing the now-unnecessary call to Unicode.tidy_bytes. Introduced about 10 years ago, that tidying step was intended to clean up invalid strings—but it added significant performance overhead. As the PR author noted: “Semantically, it makes no sense to deal with invalid strings at that layer, and performance-wise it imposes a massive overhead.”

The benchmarks speak for themselves:

current (with tidy_bytes): ~5.6 million ops/sec
no_tidy (without tidy_bytes): ~21.8 million ops/sec — nearly 4× faster!        

This is the kind of optimization that silently boosts performance without changing behavior.

Improved Exception Logging for rescue_from

This PR enhances Rails’ exception monitoring by adding logging when a rescue_from handler intercepts an exception. Traditionally, rescue_from silently swallowed exceptions in controllers, which could make debugging harder—especially when behaviors weren’t occurring as expected. By logging these incidents, Rails surfaces helpful context whenever an exception is caught and handled, without breaking existing flows.

The change introduces a log entry within the rescue_from flow (typically in controllers), enabling developers to see in the logs exactly which handler ran and for which exception:

rescue_from SomeError, with: :handle_some_error

def handle_some_error(exception)
  # Now the log will include that this exception was caught
  render ...
end        

Check the full discussion in the PR.

Allow Redirects from Configured hosts

PR #55420: apps can now safely allow redirects to domains specified in your configuration via a new allowed_redirect_hosts setting.

Before this change, the framework either raised errors or blocked redirects to unauthorized hosts, offering little flexibility for trusted external redirects. The update introduces a configuration point that makes redirect behavior both secure and adaptable.

You can configure it like this:

# config/application.rb or an environment file
config.action_controller.allowed_redirect_hosts = ["example.com", /.*\.trusted\.org/]        

With this setup, Rails now permits redirects to "example.com" or any host that matches *.trusted.org, while still guarding against unsafe or open redirect vulnerabilities.

More Rate Limit Notification Data for Instrumentation

Rails now enriches rate limit notifications with deeper context to support better observability and migration from tools like rack-attack. The change adds several useful payload attributes to the rate_limit.action_controller event—specifically: count, to, within, by, name, and cache_key.

Previously, the payload only included the request, which made it tricky to introspect or analyze throttling behavior. Now, with fields like:

  • count: how many requests have been made so far,
  • to: the allowed maximum,
  • within: the time window,
  • by: how the request is being scoped (like IP or domain),
  • name: the identifier for the rate limit rule,
  • cache_key: the key used in the cache store—

…you get a richer snapshot of what’s happening when a rate limit is hit.

Expose current_transaction.isolation to Inspect Transaction Isolation

PR #55407 — adds the connection.current_transaction.isolation API. This lets you programmatically find out the current database transaction's isolation level.

Before this change, once you entered a transaction, there wasn’t a clean, supported way in Rails to inspect what isolation level was in use. Now you can do:

ActiveRecord::Base.connection.current_transaction.isolation
# => :read_committed, :serializable, etc., if explicitly set
# => nil if no custom isolation level is set        

It even works well with nested transactions — reporting the parent transaction’s isolation level if none was set explicitly in the inner one. So, it behaves intuitively in real-world use.

relative_time_in_words Helper Added to Action View

Action View now includes a handy relative_time_in_words helper. Here’s how the new helper works in practice:

relative_time_in_words(3.minutes.from_now)             # => "in 3 minutes"
relative_time_in_words(3.minutes.ago)                   # => "3 minutes ago"
relative_time_in_words(10.seconds.ago, include_seconds: true)
                                                       # => "less than 10 seconds ago"        

This method complements existing helpers like time_ago_in_words but reads more naturally by adapting language based on whether the time is in the future or past.

Check the full PR here.

Avoid Dynamic Encryption in Generated Fixtures

In Rails PR #55387, the fixture generator got an upgrade: instead of dynamically encrypting password digests on every test run, Rails now precomputes the BCrypt hash once during fixture generation. This shift improves test consistency and performance.

Key Improvements:

  • The password_digest in fixtures is now a fixed hash, not regenerated each run.
  • A comment is included in the fixture file, e.g.
  • password_digest: <computed_hash> # Generated with BCrypt::Password.create("secret")
  • The corresponding test was updated to verify the hash is a valid BCrypt string.

Dropping JRuby Default Platforms from Gemfile.lock

Rails is now instructing Bundler not to include the default JRuby platforms unless explicitly required in your Gemfile.

Previously, Bundler often auto-included JRuby (and other default platforms) in the Gemfile.lock, which could cause confusion, mismatched dependencies, or deployment issues on non-JRuby environments—even when those gems were never used.

With this PR:

  • Bundler is prevented from automatically adding JRuby-related platforms (and possibly others) when generating the lock file.
  • Your Gemfile.lock now stays cleaner and more aligned with the platforms you actually need.
  • This helps avoid cross-platform discrepancies, improves clarity in team environments (especially when targeting MRI Ruby), and reduces unintended dependency mismatches during deployment or CI.

Check the PR here.

Making ActiveSupport::Gzip.compress Deterministic (Rails PR #55382)

Behind-the-scenes upgrade in PR #55382: ActiveSupport::Gzip.compress now produces deterministic outputs. Previously, each call generated a slightly different compressed string because a timestamp was embedded in the gzip header—making tests brittle when comparing compressed data. Now, Rails always sets the timestamp to zero during compression, ensuring that the output remains exactly the same across runs.

This practically eliminates flaky tests related to gzip comparisons. =

Fix for HashWithIndifferentAccess#transform_keys! to Prevent Key Collisions

A helpful bug fix in PR #55376 that addresses an edge case in HashWithIndifferentAccess. Previously, calling the destructive method transform_keys! could inadvertently drop keys when transformations caused duplicates—because the hash would delete a key before its new transformed key was added, leading to unexpected data loss.

With this update, Rails ensures that transformations no longer collide in a way that drops values unintentionally. If two original keys map to the same new key, their values will now be preserved correctly instead of one vanishing silently.

Why it matters:

  • Better reliability: You can confidently use transform_keys! in-place without worrying about dropped entries.
  • Safer transformations: Ensures data integrity when converting key formats (e.g., string → symbol) or case changes.

Warning for PostgreSQL 18 with Outdated pg Gem

Rails now adds a helpful compatibility check: if your application uses PostgreSQL 18 or newer but is running an older version of the pg gem (below 1.6.0), Rails will emit a warning. This addresses known compatibility issues with PG::Connection#cancel, which can break when the gem and Postgres versions don't align.

Check the full PR here.

Action Cable Redis 5.4 Compatibility Fix

Rails PR #55359 updates the Redis subscription adapter so Action Cable now works seamlessly with Redis 5.4.1, ensuring real-time features remain stable on newer Redis versions.

Remove Unnecessary Calls to the GCP Metadata Server

A thoughtful performance improvement in PR #55353. By default, calling Google::Auth.get_application_default could trigger a metadata server request on GCP—a costly operation when done frequently, such as during numerous file operations. This PR switches to a more efficient approach, recommending:

Google::Apis::RequestOptions.default.authorization = Google::Auth.get_application_default(...)        

This change avoids redundant calls to the metadata server, reducing latency and the risk of overwhelming the metadata endpoint.

Add load-hooks for Active Model Autoloaded Constants

PR #55347 adds load-hooks for ActiveModel::Error and ActiveModel::SecurePassword, and updates related configuration to utilize these hooks during class loading. This ensures that any behaviors or setups tied to those modules are applied consistently, even when they're autoloaded.

has_secure_password Validation Fix

PR #55232 improves the behavior of the has_secure_password validation. Previously, setting the password attribute to nil could cause unexpected validation failure, even when a password wasn’t required. This update ensures that password validation now handles nil values correctly, making authentication-related tests and logic more reliable.

Health Check Endpoint Now Supports JSON Responses

PR #55092 enhances the default health check endpoint (typically accessible at /up) by allowing it to respond in JSON format in addition to plain text. This enables smoother integration with monitoring tools and services that parse structured responses.

Before, hitting /up would return a simple 200 OK response with no body or plain text; now, you can request JSON output for more informative and machine-readable health checks.

Add ActiveRecord::Tasks::AbstractTasks for Adapter Customization

A useful enhancement in PR #54879: the introduction of ActiveRecord::Tasks::AbstractTasks. This change enables developers to subclass and customize task behaviors (e.g., db:drop, db:setup) on a per-database-adapter basis—without patching the core tasks directly.

It was motivated by scenarios like SQLite3 running in read-only mode on Linux, where default behavior fails (check_current_protected_environment!). With this abstract base, adapters can override these behaviors cleanly and explicitly.

nonce: false Now Truly Omits the nonce Attribute

Rails has refined how nonce: false behaves in view helper tags with this enhancement, now merged in PR #54724. Previously, passing nonce: false to javascript_tag, javascript_include_tag, or stylesheet_link_tag would generate nonce="false" in the HTML—effectively a misleading attribute. Now, setting nonce: false completely omits the nonce attribute, aligning behavior with developer expectations.

Key change summary:

  • nonce: true → adds nonce="..." as expected.
  • nonce: false → now does not add any nonce attribute at all, instead of nonce="false".
  • A changelog entry was also included to document this behavior fix.github.com

Customizable Domain Extraction in ActionDispatch::Http::URL

Rails now lets you plug in your own domain extraction logic when parsing URLs, thanks to PR #50763. Previously, ActionDispatch::Http::URL used a fixed strategy to extract the domain from request URLs. With this update, you can swap in a custom extractor class—perfect for handling specialized domain patterns, IPs, or nonstandard hosts.

# Example: Rails.config set to use your custom domain logic
Rails.application.config.action_dispatch.domain_extractor = MyCustomDomainExtractor        

Read ActionText::Attachment.tag_name in Action Text Fixtures

Utilizing the ActionText::FixtureSet.attachment method in consumer application’s test suites relies on a hard-coded action-text-attachment element tag name. While it's uncommon for that value to change, it is possible to configure it with the config.action_text.attachment_tag_name configuration.

This commit replaces the hard-coded name by interpolating ActionText::Attachment.tag_name.

Internal to the Rails test suite, Action Text’s fixtures use HTML with <p> elements to wrap new blocks of text. Trix uses <div> elements by default for line breaking (and for other historical reasons). This change is internal to this codebase, and will not affect users.

PR here.

Streamlining the Public API of the tag Helper

Rails has recently cleaned up its internal API by reducing the number of publicly exposed methods in the ActionView::Helpers::TagHelper module, specifically around the tag helper. With this change, more lower-level methods—such as build_tag_values and others—have been moved out of the public interface scope, making the API surface slimmer and clearer for developers.

This keeps the public API focused on what’s actually meant for use, reducing confusion and improving long-term maintainability. You can check out the full implementation and discussion in PR #49369.

Add touch Option to update_columns and update_column

A neat improvement in PR #51455: you can now pass touch: true when using update_columns or update_column to automatically update the model's timestamp—just like the regular touch method does.

Before this change, if you used these methods, you’d have to manually call touch to update timestamps—especially when working with ETL flows or bypassing model callbacks. Now, it's as simple as:

user.update_columns(name: "Alice", touch: true)        

Open Files from the Crash Page in Your Editor

Quality-of-life feature in PR #55295: now, when you’re looking at a crash page in development, you’ll see links that open the exact file and line in your local code editor.

Developers can configure their editor via the EDITOR environment variable—popular ones like VSCode, Emacs, IntelliJ, MacVim, etc., are supported out of the box. The feature is implemented via TraceToFileExtractor an editor registration logic, now neatly organized within ActiveSupport.

Fix for Invalid Query String Key Errors

Fix in PR #55319 that prevents 500 errors when the keys in a query string have invalid encoding. The patch adds a validation step in the query string parser to ensure keys are properly encoded, defusing errors caused by malformed requests — which were commonly triggered by bots.

Importantly, the change doesn’t affect performance, with benchmarks showing nearly identical speed before and after the fix.

require "benchmark/ips"

require "action_dispatch"
require "active_support/all"

require_relative "param_builder"
require_relative "param_builder_original"

QUERY_STRING = "foo=bar"
QUERY_STRING_INVALID = "foo=%81E"

def check_param_encoding
  request_params = ActionDispatch::ParamBuilder.from_query_string(QUERY_STRING, encoding_template: nil)
  request_params.inspect
end

def check_param_encoding_original
  request_params = ActionDispatch::ParamBuilderOriginal.from_query_string(QUERY_STRING, encoding_template: nil)
  request_params.inspect
end


Benchmark.ips do |x|
  x.report("new") { check_param_encoding }
  x.report("original") { check_param_encoding_original }

  x.compare!
end        
$ bundle exec ruby benchmark.rb
ruby 3.3.5 (2024-09-03 revision ef084cc8f4) [arm64-darwin24]
Warming up --------------------------------------
                 new    40.767k i/100ms
            original    41.113k i/100ms
Calculating -------------------------------------
                 new    408.540k (± 1.5%) i/s    (2.45 μs/i) -      2.079M in   5.090267s
            original    408.498k (± 3.2%) i/s    (2.45 μs/i) -      2.056M in   5.037672s

Comparison:
                 new:   408540.0 i/s
            original:   408498.2 i/s - same-ish: difference falls within error        

Fix Migration Log Message for down Operations

Simple yet valuable update in PR #52749: it fixes the migration log messaging for down (rollback) operations. Before, rolling back migrations could result in misleading or ambiguous log entries, making it harder to follow what was happening. This change ensures that logs accurately reflect rollback actions, helping developers—and anyone reading the history—understand the exact migration flow.

Raise Error for Order-Dependent Finder Methods Without an ORDER Clause

A new error handling improvement via this pull request: methods like last and find_nth now raise a clear, descriptive error when used on models without an ORDER clause defined. This replaces silent or undefined behavior with a precise exception—likely ActiveRecord::MissingRequiredOrderError—making it much more obvious when you're trying to perform order-dependent operations without specifying how records should be ordered.

PR here.

Return a 500 on MissingController Errors

Rails now treats a missing controller as a programming error rather than a typical routing error. When a controller doesn’t exist, Rails will respond with a 500 Internal Server Error instead of a 404. This ensures that such issues — typically bugs, typos, or routing misconfigurations — are surfaced during development and properly logged, rather than silently hidden behind a “not found” response.

PR here.

Optimize Active Record Batching with in_batches(use_ranges: true)

Rails has streamlined its batch-loading performance with a clever update in PR #51243. Now, when using in_batches(use_ranges: true), Rails avoids transferring every ID across the network—choosing instead to use OFFSET to efficiently fetch just the last ID needed for each batch.

Before this change, Rails ran a query like:

SELECT id FROM users WHERE id > 10000 ORDER BY id ASC LIMIT 10000;        

Even though only the last ID was used, the rest were still retrieved and discarded.

Now it runs:

SELECT id FROM users WHERE id > ... ORDER BY id ASC LIMIT 1 OFFSET 9999;        

This grabs just the last ID in each batch, reducing network traffic and resource usage significantly — benchmarks show ~2.4× faster performance and 900× less bandwidth usage. For tables with billions of records, these improvements are game-changing.

SafeBuffer Optimization for Action Text

PR #55352: SafeBuffer objects in Action Text are now optimized for better performance.

The normalize_action_path Nodoc Fix

ActionController::RequestForgeryProtection. Thanks to PR #55317, the method normalize_action_path, which was previously appearing in API docs despite being internal-only, has now been marked with nodoc. This means it will no longer be visible in the public documentation—keeping things cleaner and more focused for developers.


And that is it for this month's edition of Ruby on Rails Monthly.

As we wrap up this month’s updates, it’s clear that Rails continues to refine not only its features but also its developer experience, from subtle documentation cleanups to impactful improvements under the hood. Each of these changes, big or small, helps shape a more stable, reliable, and enjoyable framework for all of us. I’ll be keeping an eye on the next wave of enhancements and will share the highlights with you in the upcoming edition. Until then, happy coding and keep building great things with Rails!

To view or add a comment, sign in

More articles by Sajjad Umar

  • Ruby On Rails — Sep 2025

    Rails World — All Talks Out Now you can watch all your favorite sessions of Rails World 2025 on YouTube Rails 8.1 Beta…

  • Ruby on Rails — June 2025

    All the Rails News That Matters, Once a Month! Hey everyone — Sajjad Umar here with the June edition of Ruby on Rails…

  • Ruby on Rails - May 2025

    Hey everyone — Sajjad Umar here with the May edition of Ruby on Rails Monthly! ☀️ The year’s moving fast, and May…

  • Ruby on Rails - April 2025

    All the Rails News That Matters, Once a Month. Hey folks — Sajjad Umar here with the April edition of Ruby on Rails…

  • Ruby on Rails — March 2025

    All the Rails News That Matters, Once a Month. Ramadan Kareem! 🌙 Wishing you all peace, blessings, and a month filled…

  • Ruby on Rails - Feb 2025

    All the Rails News That Matters, Once a Month. Hey everyone—Sajjad Umar here with the February edition of Ruby on Rails…

  • Ruby on Rails — Jan 2025

    All the Rails News That Matters, Once a Month. Happy New Year, everyone! 🎉 This is Sajjad Umar, kicking off 2025 with…

  • Ruby on Rails — Dec 2024

    It's the only Ruby on Rails newsletter you will ever need! Hey guys — this is Sajjad Umar back with another edition of…

  • Ruby on Rails - Nov 2024 (Edition #35)

    Welcome to the 35th Edition of Ruby on Rails Monthly - Sajjad here with some exciting updates from Ruby on Rails world.…

  • Ruby on Rails - Oct 2024

    The only Ruby on Rails newsletter you will ever need! Hey Ruby folks — this is a fascinating month for the Ruby on…

Others also viewed

Explore content categories