Update Ruby production dependencies
This MR contains the following updates:
| Package | Update | Change | MyDiffEnd |
|---|---|---|---|
| puma | minor |
'>= 7.0.4' -> '>= 7.1.0'
|
https://my.diffend.io/gems/puma/7.0.4/7.1.0 |
| rails (source, changelog) | minor |
'~> 8.0.3' -> '~> 8.1.0'
|
https://my.diffend.io/gems/rails/8.0.3/8.1.0 |
MR created with the help of gitlab-org/frontend/renovate-gitlab-bot
Release Notes
rails/rails (rails)
v8.1.0: 8.1.0
Active Support
-
Remove deprecated passing a Time object to
Time#since.Rafael Mendonça França
-
Remove deprecated
Benchmark.msmethod. It is now defined in thebenchmarkgem.Rafael Mendonça França
-
Remove deprecated addition for
Timeinstances withActiveSupport::TimeWithZone.Rafael Mendonça França
-
Remove deprecated support for
to_timeto preserve the system local time. It will now always preserve the receiver timezone.Rafael Mendonça França
-
Deprecate
config.active_support.to_time_preserves_timezone.Rafael Mendonça França
-
Standardize event name formatting in
assert_event_reportederror messages.The event name in failure messages now uses
.inspect(e.g.,name: "user.created") to matchassert_events_reportedand provide type clarity between strings and symbols. This only affects tests that assert on the failure message format itself.George Ma
-
Fix
Enumerable#soleto return the full tuple instead of just the first element of the tuple.Olivier Bellone
-
Fix parallel tests hanging when worker processes die abruptly.
Previously, if a worker process was killed (e.g., OOM killed,
kill -9) during parallel test execution, the test suite would hang forever waiting for the dead worker.Joshua Young
-
Add
config.active_support.escape_js_separators_in_json.Introduce a new framework default to skip escaping LINE SEPARATOR (U+2028) and PARAGRAPH SEPARATOR (U+2029) in JSON.
Historically these characters were not valid inside JavaScript literal strings but that changed in ECMAScript 2019. As such it's no longer a concern in modern browsers: https://caniuse.com/mdn-javascript_builtins_json_json_superset.
Étienne Barrié, Jean Boussier
-
Fix
NameErrorwhenclass_attributeis defined on instance singleton classes.Previously, calling
class_attributeon an instance's singleton class would raise aNameErrorwhen accessing the attribute through the instance.object = MyClass.new object.singleton_class.class_attribute :foo, default: "bar" object.foo # previously raised NameError, now returns "bar"Joshua Young
-
Introduce
ActiveSupport::Testing::EventReporterAssertions#with_debug_event_reportingto enable event reporter debug mode in tests.The previous way to enable debug mode is by using
#with_debugon the event reporter itself, which is too verbose. This new helper will help clear up any confusion on how to test debug events.Gannon McGibbon
-
Add
ActiveSupport::StructuredEventSubscriberfor consuming notifications and emitting structured event logs. Events may be emitted with the#emit_eventor#emit_debug_eventmethods.class MyStructuredEventSubscriber < ActiveSupport::StructuredEventSubscriber def notification(event) emit_event("my.notification", data: 1) end endAdrianna Chang
-
ActiveSupport::FileUpdateCheckerdoes not depend onTime.nowto prevent unecessary reloads with time travel test helpersJan Grodowski
-
Add
ActiveSupport::Cache::Store#namespace=and#namespace.Can be used as an alternative to
Store#clearin some situations such as parallel testing.Nick Schwaderer
-
Create
parallel_worker_idhelper for running parallel tests. This allows users to know which worker they are currently running in.Nick Schwaderer
-
Make the cache of
ActiveSupport::Cache::Strategy::LocalCache::Middlewareupdatable.If the cache client at
Rails.cacheof a booted application changes, the corresponding mounted middleware needs to update in order for request-local caches to be setup properly. Otherwise, redundant cache operations will erroneously hit the datastore.Gannon McGibbon
-
Add
assert_events_reportedtest helper forActiveSupport::EventReporter.This new assertion allows testing multiple events in a single block, regardless of order:
assert_events_reported([ { name: "user.created", payload: { id: 123 } }, { name: "email.sent", payload: { to: "user@example.com" } } ]) do create_user_and_send_welcome_email endGeorge Ma
-
Add
ActiveSupport::TimeZone#standard_namemethod.zone = ActiveSupport::TimeZone['Hawaii']
Old way
ActiveSupport::TimeZone::MAPPING[zone.name]
New way
zone.standard_name # => 'Pacific/Honolulu'
```
*Bogdan Gusiev*
-
Add Structured Event Reporter, accessible via
Rails.event.The Event Reporter provides a unified interface for producing structured events in Rails applications:
Rails.event.notify("user.signup", user_id: 123, email: "user@example.com")It supports adding tags to events:
Rails.event.tagged("graphql") do
Event includes tags: { graphql: true }
Rails.event.notify("user.signup", user_id: 123, email: "user@example.com")
end
```
As well as context:
```ruby
All events will contain context: {request_id: "abc123", shop_id: 456}
Rails.event.set_context(request_id: "abc123", shop_id: 456)
```
Events are emitted to subscribers. Applications register subscribers to
control how events are serialized and emitted. Subscribers must implement
an `#emit` method, which receives the event hash:
```ruby
class LogSubscriber
def emit(event)
payload = event[:payload].map { |key, value| "#{key}=#{value}" }.join(" ")
source_location = event[:source_location]
log = "[#{event[:name]}] #{payload} at #{source_location[:filepath]}:#{source_location[:lineno]}"
Rails.logger.info(log)
end
end
```
*Adrianna Chang*
-
Make
ActiveSupport::Logger#freeze-friendly.Joshua Young
-
Make
ActiveSupport::Gzip.compressdeterministic based on input.ActiveSupport::Gzip.compressused to include a timestamp in the output, causing consecutive calls with the same input data to have different output if called during different seconds. It now always sets the timestamp to0so that the output is identical for any given input.Rob Brackett
-
Given an array of
Thread::Backtrace::Locationobjects, the new methodActiveSupport::BacktraceCleaner#clean_locationsreturns an array with the clean ones:clean_locations = backtrace_cleaner.clean_locations(caller_locations)Filters and silencers receive strings as usual. However, the
pathattributes of the locations in the returned array are the original, unfiltered ones, since locations are immutable.Xavier Noria
-
Improve
CurrentAttributesandExecutionContextstate managment in test cases.Previously these two global state would be entirely cleared out whenever calling into code that is wrapped by the Rails executor, typically Action Controller or Active Job helpers:
test "#index works" do CurrentUser.id = 42 get :index CurrentUser.id == nil endNow re-entering the executor properly save and restore that state.
Jean Boussier
-
The new method
ActiveSupport::BacktraceCleaner#first_clean_locationreturns the first clean location of the caller's call stack, ornil. Locations areThread::Backtrace::Locationobjects. Useful when you want to report the application-level location where something happened as an object.Xavier Noria
-
FileUpdateChecker and EventedFileUpdateChecker ignore changes in Gem.path now.
Ermolaev Andrey, zzak
-
The new method
ActiveSupport::BacktraceCleaner#first_clean_framereturns the first clean frame of the caller's backtrace, ornil. Useful when you want to report the application-level frame where something happened as a string.Xavier Noria
-
Always clear
CurrentAttributesinstances.Previously
CurrentAttributesinstance would be reset at the end of requests. Meaning its attributes would be re-initialized.This is problematic because it assume these objects don't hold any state other than their declared attribute, which isn't always the case, and can lead to state leak across request.
Now
CurrentAttributesinstances are abandoned at the end of a request, and a new instance is created at the start of the next request.Jean Boussier, Janko Marohnić
-
Add public API for
before_fork_hookin parallel testing.Introduces a public API for calling the before fork hooks implemented by parallel testing.
parallelize_before_fork do
perform an action before test processes are forked
end
```
*Eileen M. Uchitelle*
-
Implement ability to skip creating parallel testing databases.
With parallel testing, Rails will create a database per process. If this isn't desirable or you would like to implement databases handling on your own, you can now turn off this default behavior.
To skip creating a database per process, you can change it via the
parallelizemethod:parallelize(workers: 10, parallelize_databases: false)or via the application configuration:
config.active_support.parallelize_databases = falseEileen M. Uchitelle
-
Allow to configure maximum cache key sizes
When the key exceeds the configured limit (250 bytes by default), it will be truncated and the digest of the rest of the key appended to it.
Note that previously
ActiveSupport::Cache::RedisCacheStoreallowed up to 1kb cache keys before truncation, which is now reduced to 250 bytes.config.cache_store = :redis_cache_store, { max_key_size: 64 }fatkodima
-
Use
UNLINKcommand instead ofDELinActiveSupport::Cache::RedisCacheStorefor non-blocking deletion.Aron Roh
-
Add
Cache#read_counterandCache#write_counterRails.cache.write_counter("foo", 1) Rails.cache.read_counter("foo") # => 1 Rails.cache.increment("foo") Rails.cache.read_counter("foo") # => 2Alex Ghiculescu
-
Introduce ActiveSupport::Testing::ErrorReporterAssertions#capture_error_reports
Captures all reported errors from within the block that match the given error class.
reports = capture_error_reports(IOError) do Rails.error.report(IOError.new("Oops")) Rails.error.report(IOError.new("Oh no")) Rails.error.report(StandardError.new) end assert_equal 2, reports.size assert_equal "Oops", reports.first.error.message assert_equal "Oh no", reports.last.error.messageAndrew Novoselac
-
Introduce ActiveSupport::ErrorReporter#add_middleware
When reporting an error, the error context middleware will be called with the reported error and base execution context. The stack may mutate the context hash. The mutated context will then be passed to error subscribers. Middleware receives the same parameters as
ErrorReporter#report.Andrew Novoselac, Sam Schmidt
-
Change execution wrapping to report all exceptions, including
Exception.If a more serious error like
SystemStackErrororNoMemoryErrorhappens, the error reporter should be able to report these kinds of exceptions.Gannon McGibbon
-
ActiveSupport::Testing::Parallelization.before_fork_hookallows declaration of callbacks that are invoked immediately before forking test workers.Mike Dalessio
-
Allow the
#freeze_timetesting helper to accept a date or time argument.Time.current # => Sun, 09 Jul 2024 15:34:49 EST -05:00 freeze_time Time.current + 1.day sleep 1 Time.current # => Mon, 10 Jul 2024 15:34:49 EST -05:00Joshua Young
-
ActiveSupport::JSONnow accepts optionsIt is now possible to pass options to
ActiveSupport::JSON:ActiveSupport::JSON.decode('{"key": "value"}', symbolize_names: true) # => { key: "value" }matthaigh27
-
ActiveSupport::Testing::NotificationAssertions'sassert_notificationnow matches against payload subsets by default.Previously the following assertion would fail due to excess key vals in the notification payload. Now with payload subset matching, it will pass.
assert_notification("post.submitted", title: "Cool Post") do ActiveSupport::Notifications.instrument("post.submitted", title: "Cool Post", body: "Cool Body") endAdditionally, you can now persist a matched notification for more customized assertions.
notification = assert_notification("post.submitted", title: "Cool Post") do ActiveSupport::Notifications.instrument("post.submitted", title: "Cool Post", body: Body.new("Cool Body")) end assert_instance_of(Body, notification.payload[:body])Nicholas La Roux
-
Deprecate
String#mb_charsandActiveSupport::Multibyte::Chars.These APIs are a relic of the Ruby 1.8 days when Ruby strings weren't encoding aware. There is no legitimate reasons to need these APIs today.
Jean Boussier
-
Deprecate
ActiveSupport::ConfigurableSean Doyle
-
nil.to_query("key")now returnskey.Previously it would return
key=, preventing round tripping withRack::Utils.parse_nested_query.Erol Fornoles
-
Avoid wrapping redis in a
ConnectionPoolwhen usingActiveSupport::Cache::RedisCacheStoreif the:redisoption is already aConnectionPool.Joshua Young
-
Alter
ERB::Util.tokenizeto return :PLAIN token with full input string when string doesn't contain ERB tags.Martin Emde
-
Fix a bug in
ERB::Util.tokenizethat causes incorrect tokenization when ERB tags are preceded by multibyte characters.Martin Emde
-
Add
ActiveSupport::Testing::NotificationAssertionsmodule to help with testingActiveSupport::Notifications.Nicholas La Roux, Yishu See, Sean Doyle
-
ActiveSupport::CurrentAttributes#attributesnow will return a new hash object on each call.Previously, the same hash object was returned each time that method was called.
fatkodima
-
ActiveSupport::JSON.encodesupports CIDR notation.Previously:
ActiveSupport::JSON.encode(IPAddr.new("172.16.0.0/24")) # => "\"172.16.0.0\""After this change:
ActiveSupport::JSON.encode(IPAddr.new("172.16.0.0/24")) # => "\"172.16.0.0/24\""Taketo Takashima
-
Make
ActiveSupport::FileUpdateCheckerfaster when checking many file-extensions.Jonathan del Strother
Active Model
-
Add
reset_token: { expires_in: ... }option tohas_secure_password.Allows configuring the expiry duration of password reset tokens (default remains 15 minutes for backwards compatibility).
has_secure_password reset_token: { expires_in: 1.hour }Jevin Sew, Abeid Ahmed
-
Add
except_on:option for validation callbacks.Ben Sheldon
-
Backport
ActiveRecord::NormalizationtoActiveModel::Attributes::Normalizationclass User include ActiveModel::Attributes include ActiveModel::Attributes::Normalization attribute :email, :string normalizes :email, with: -> email { email.strip.downcase } end user = User.new user.email = " CRUISE-CONTROL@EXAMPLE.COM\n" user.email # => "cruise-control@example.com"Sean Doyle
Active Record
-
Fix SQLite3 data loss during table alterations with CASCADE foreign keys.
When altering a table in SQLite3 that is referenced by child tables with
ON DELETE CASCADEforeign keys, ActiveRecord would silently delete all data from the child tables. This occurred because SQLite requires table recreation for schema changes, and during this process the original table is temporarily dropped, triggering CASCADE deletes on child tables.The root cause was incorrect ordering of operations. The original code wrapped
disable_referential_integrityinside a transaction, butPRAGMA foreign_keyscannot be modified inside a transaction in SQLite - attempting to do so simply has no effect. This meant foreign keys remained enabled during table recreation, causing CASCADE deletes to fire.The fix reverses the order to follow the official SQLite 12-step ALTER TABLE procedure:
disable_referential_integritynow wraps the transaction instead of being wrapped by it. This ensures foreign keys are properly disabled before the transaction starts and re-enabled after it commits, preventing CASCADE deletes while maintaining data integrity through atomic transactions.Ruy Rocha
-
Add replicas to test database parallelization setup.
Setup and configuration of databases for parallel testing now includes replicas.
This fixes an issue when using a replica database, database selector middleware, and non-transactional tests, where integration tests running in parallel would select the base test database, i.e.
db_test, instead of the numbered parallel worker database, i.e.db_test_{n}.Adam Maas
-
Support virtual (not persisted) generated columns on PostgreSQL 18+
PostgreSQL 18 introduces virtual (not persisted) generated columns, which are now the default unless the
stored: trueoption is explicitly specified on PostgreSQL 18+.create_table :users do |t| t.string :name t.virtual :lower_name, type: :string, as: "LOWER(name)", stored: false t.virtual :name_length, type: :integer, as: "LENGTH(name)" endYasuo Honda
-
Optimize schema dumping to prevent duplicate file generation.
ActiveRecord::Tasks::DatabaseTasks.dump_allnow tracks which schema files have already been dumped and skips dumping the same file multiple times. This improves performance when multiple database configurations share the same schema dump path.Mikey Gough, Hartley McGuire
-
Add structured events for Active Record:
active_record.strict_loading_violationactive_record.sql
Gannon McGibbon
-
Add support for integer shard keys.
Now accepts symbols as shard keys.
ActiveRecord::Base.connects_to(shards: {
1: { writing: :primary_shard_one, reading: :primary_shard_one },
2: { writing: :primary_shard_two, reading: :primary_shard_two},
})
ActiveRecord::Base.connected_to(shard: 1) do
..
end
```
*Nony Dutton*
-
Add
ActiveRecord::Base.only_columnsSimilar in use case to
ignored_columnsbut listing columns to consider rather than the ones to ignore.Can be useful when working with a legacy or shared database schema, or to make safe schema change in two deploys rather than three.
Anton Kandratski
-
Use
PG::Connection#close_prepared(protocol level Close) to deallocate prepared statements when available.To enable its use, you must have pg >= 1.6.0, libpq >= 17, and a PostgreSQL database version >= 17.
Hartley McGuire, Andrew Jackson
-
Fix query cache for pinned connections in multi threaded transactional tests
When a pinned connection is used across separate threads, they now use a separate cache store for each thread.
This improve accuracy of system tests, and any test using multiple threads.
Heinrich Lee Yu, Jean Boussier
-
Fix time attribute dirty tracking with timezone conversions.
Time-only attributes now maintain a fixed date of 2000-01-01 during timezone conversions, preventing them from being incorrectly marked as changed due to date shifts.
This fixes an issue where time attributes would be marked as changed when setting the same time value due to timezone conversion causing internal date shifts.
Prateek Choudhary
-
Skip calling
PG::Connection#cancelincancel_any_running_querywhen using libpq >= 18 with pg < 1.6.0, due to incompatibility. Rollback still runs, but may take longer.Yasuo Honda, Lars Kanis
-
Don't add
id_valueattribute alias when attribute/column with that name already exists.Rob Lewis
-
Remove deprecated
:unsigned_floatand:unsigned_decimalcolumn methods for MySQL.Rafael Mendonça França
-
Remove deprecated
:retriesoption for the SQLite3 adapter.Rafael Mendonça França
-
Introduce new database configuration options
keepalive,max_age, andmin_connections-- and renamepooltomax_connectionsto match.There are no changes to default behavior, but these allow for more specific control over pool behavior.
Matthew Draper, Chris AtLee, Rachael Wright-Munn
-
Move
LIMITvalidation from query generation to whenlimit()is called.Hartley McGuire, Shuyang
-
Add
ActiveRecord::CheckViolationerror class for check constraint violations.Ryuta Kamizono
-
Add
ActiveRecord::ExclusionViolationerror class for exclusion constraint violations.When an exclusion constraint is violated in PostgreSQL, the error will now be raised as
ActiveRecord::ExclusionViolationinstead of the genericActiveRecord::StatementInvalid, making it easier to handle these specific constraint violations in application code.This follows the same pattern as other constraint violation error classes like
RecordNotUniquefor unique constraint violations andInvalidForeignKeyfor foreign key constraint violations.Ryuta Kamizono
-
Attributes filtered by
filter_attributeswill now also be filtered byfilter_parametersso sensitive information is not leaked.Jill Klang
-
Add
connection.current_transaction.isolationAPI to check current transaction's isolation level.Returns the isolation level if it was explicitly set via the
isolation:parameter or throughActiveRecord.with_transaction_isolation_level, otherwise returnsnil. Nested transactions return the parent transaction's isolation level.
Returns nil when no transaction
User.connection.current_transaction.isolation # => nil
Returns explicitly set isolation level
User.transaction(isolation: :serializable) do
User.connection.current_transaction.isolation # => :serializable
end
Returns nil when isolation not explicitly set
User.transaction do
User.connection.current_transaction.isolation # => nil
end
Nested transactions inherit parent's isolation
User.transaction(isolation: :read_committed) do
User.transaction do
User.connection.current_transaction.isolation # => :read_committed
end
end
```
*Kir Shatrov*
-
Fix
#mergewith#oror#andand a mixture of attributes and SQL strings resulting in an incorrect query.base = Comment.joins(:post).where(user_id: 1).where("recent = 1") puts base.merge(base.where(draft: true).or(Post.where(archived: true))).to_sqlBefore:
SELECT "comments".* FROM "comments" INNER JOIN "posts" ON "posts"."id" = "comments"."post_id" WHERE (recent = 1) AND ( "comments"."user_id" = 1 AND (recent = 1) AND "comments"."draft" = 1 OR "posts"."archived" = 1 )After:
SELECT "comments".* FROM "comments" INNER JOIN "posts" ON "posts"."id" = "comments"."post_id" WHERE "comments"."user_id" = 1 AND (recent = 1) AND ( "comments"."user_id" = 1 AND (recent = 1) AND "comments"."draft" = 1 OR "posts"."archived" = 1 )Joshua Young
-
Make schema dumper to account for
ActiveRecord.dump_schemaswhen dumping in:rubyformat.fatkodima
-
Add
:touchoption toupdate_column/update_columnsmethods.
Will update :updated_at/:updated_on alongside :nice column.
user.update_column(:nice, true, touch: true)
Will update :updated_at/:updated_on alongside :last_ip column
user.update_columns(last_ip: request.remote_ip, touch: true)
```
*Dmitrii Ivliev*
-
Optimize Active Record batching further when using ranges.
Tested on a PostgreSQL table with 10M records and batches of 10k records, the generation of relations for the 1000 batches was
4.8xfaster (6.8svs.1.4s), used900xless bandwidth (180MBvs.0.2MB) and allocated45xless memory (490MBvs.11MB).Maxime Réty, fatkodima
-
Include current character length in error messages for index and table name length validations.
Joshua Young
-
Add
rename_schemamethod for PostgreSQL.T S Vallender
-
Implement support for deprecating associations:
has_many :posts, deprecated: trueWith that, Active Record will report any usage of the
postsassociation.Three reporting modes are supported (
:warn,:raise, and:notify), and backtraces can be enabled or disabled. Defaults are:warnmode and disabled backtraces.Please, check the docs for further details.
Xavier Noria
-
PostgreSQL adapter create DB now supports
locale_providerandlocale.Bengt-Ove Hollaender
-
Use ntuples to populate row_count instead of count for Postgres
Jonathan Calvert
-
Fix checking whether an unpersisted record is
include?d in a strictly loadedhas_and_belongs_to_manyassociation.Hartley McGuire
-
Add ability to change transaction isolation for all pools within a block.
This functionality is useful if your application needs to change the database transaction isolation for a request or action.
Calling
ActiveRecord.with_transaction_isolation_level(level) {}in an around filter or middleware will set the transaction isolation for all pools accessed within the block, but not for the pools that aren't.This works with explicit and implicit transactions:
ActiveRecord.with_transaction_isolation_level(:read_committed) do Tag.transaction do # opens a transaction explicitly Tag.create! end endActiveRecord.with_transaction_isolation_level(:read_committed) do Tag.create! # opens a transaction implicitly endEileen M. Uchitelle
-
Raise
ActiveRecord::MissingRequiredOrderErrorwhen order dependent finder methods (e.g.#first,#last) are called withoutordervalues on the relation, and the model does not have any order columns (implicit_order_column,query_constraints, orprimary_key) to fall back on.This change will be introduced with a new framework default for Rails 8.1, and the current behavior of not raising an error has been deprecated with the aim of removing the configuration option in Rails 8.2.
config.active_record.raise_on_missing_required_finder_order_columns = trueJoshua Young
-
:class_nameis now invalid in polymorphicbelongs_toassociations.Reason is
:class_namedoes not make sense in those associations because the class name of target records is dynamic and stored in the type column.Existing polymorphic associations setting this option can just delete it. While it did not raise, it had no effect anyway.
Xavier Noria
-
Add support for multiple databases to
db:migrate:reset.Joé Dupuis
-
Add
affected_rowstoActiveRecord::Result.Jenny Shen
-
Enable passing retryable SqlLiterals to
#where.Hartley McGuire
-
Set default for primary keys in
insert_all/upsert_all.Previously in Postgres, updating and inserting new records in one upsert wasn't possible due to null primary key values.
nilprimary key values passed intoinsert_all/upsert_allare now implicitly set to the default insert value specified by adapter.Jenny Shen
-
Add a load hook
active_record_database_configurationsforActiveRecord::DatabaseConfigurationsMike Dalessio
-
Use
TRUEandFALSEfor SQLite queries with boolean columns.Hartley McGuire
-
Bump minimum supported SQLite to 3.23.0.
Hartley McGuire
-
Allow allocated Active Records to lookup associations.
Previously, the association cache isn't setup on allocated record objects, so association lookups will crash. Test frameworks like mocha use allocate to check for stubbable instance methods, which can trigger an association lookup.
Gannon McGibbon
-
Encryption now supports
support_unencrypted_data: truebeing set per-attribute.Previously this only worked if
ActiveRecord::Encryption.config.support_unencrypted_data == true. Now, if the global config is turned off, you can still opt in for a specific attribute.
ActiveRecord::Encryption.config.support_unencrypted_data = true
class User < ActiveRecord::Base
encrypts :name, support_unencrypted_data: false # only supports encrypted data
encrypts :email # supports encrypted or unencrypted data
end
```
```ruby
ActiveRecord::Encryption.config.support_unencrypted_data = false
class User < ActiveRecord::Base
encrypts :name, support_unencrypted_data: true # supports encrypted or unencrypted data
encrypts :email # only supports encrypted data
end
```
*Alex Ghiculescu*
-
Model generator no longer needs a database connection to validate column types.
Mike Dalessio
-
Allow signed ID verifiers to be configurable via
Rails.application.message_verifiersPrior to this change, the primary way to configure signed ID verifiers was to set
signed_id_verifieron each model class:Post.signed_id_verifier = ActiveSupport::MessageVerifier.new(...) Comment.signed_id_verifier = ActiveSupport::MessageVerifier.new(...)And if the developer did not set
signed_id_verifier, a verifier would be instantiated with a secret derived fromsecret_key_baseand the following options:{ digest: "SHA256", serializer: JSON, url_safe: true }Thus it was cumbersome to rotate configuration for all verifiers.
This change defines a new Rails config: [
config.active_record.use_legacy_signed_id_verifier][]. The default value is:generate_and_verify, which preserves the previous behavior. However, when set to:verify, signed ID verifiers will use configuration fromRails.application.message_verifiers(specifically,Rails.application.message_verifiers["active_record/signed_id"]) to generate and verify signed IDs, but will also verify signed IDs using the older configuration.To avoid complication, the new behavior only applies when
signed_id_verifier_secretis not set on a model class or any of its ancestors. Additionally,signed_id_verifier_secretis now deprecated. If you are currently settingsigned_id_verifier_secreton a model class, you can setsigned_id_verifierinstead:
BEFORE
Post.signed_id_verifier_secret = "my secret"
AFTER
Post.signed_id_verifier = ActiveSupport::MessageVerifier.new("my secret", digest: "SHA256", serializer: JSON, url_safe: true)
```
To ease migration, `signed_id_verifier` has also been changed to behave as a
`class_attribute` (i.e. inheritable), but _only when `signed_id_verifier_secret`
is not set_:
```ruby
BEFORE
ActiveRecord::Base.signed_id_verifier = ActiveSupport::MessageVerifier.new(...)
Post.signed_id_verifier == ActiveRecord::Base.signed_id_verifier # => false
AFTER
ActiveRecord::Base.signed_id_verifier = ActiveSupport::MessageVerifier.new(...)
Post.signed_id_verifier == ActiveRecord::Base.signed_id_verifier # => true
Post.signed_id_verifier_secret = "my secret" # => deprecation warning
Post.signed_id_verifier == ActiveRecord::Base.signed_id_verifier # => false
```
Note, however, that it is recommended to eventually migrate from
model-specific verifiers to a unified configuration managed by
`Rails.application.message_verifiers`. `ActiveSupport::MessageVerifier#rotate`
can facilitate that transition. For example:
```ruby
BEFORE
Generate and verify signed Post IDs using Post-specific configuration
Post.signed_id_verifier = ActiveSupport::MessageVerifier.new("post secret", ...)
AFTER
Generate and verify signed Post IDs using the unified configuration
Post.signed_id_verifier = Post.signed_id_verifier.dup
Fall back to Post-specific configuration when verifying signed IDs
Post.signed_id_verifier.rotate("post secret", ...)
```
[`config.active_record.use_legacy_signed_id_verifier`]: https://guides.rubyonrails.org/v8.1/configuring.html#config-active-record-use-legacy-signed-id-verifier
*Ali Sepehri*, *Jonathan Hefner*
-
Prepend
extra_flagsin postgres'structure_loadWhen specifying
structure_load_flagswith a postgres adapter, the flags were appended to the default flags, instead of prepended. This caused issues with flags not being taken into account by postgres.Alice Loeser
-
Allow bypassing primary key/constraint addition in
implicit_order_columnWhen specifying multiple columns in an array for
implicit_order_column, addingnilas the last element will prevent appending the primary key to order conditions. This allows more precise control of indexes used by generated queries. It should be noted that this feature does introduce the risk of API misbehavior if the specified columns are not fully unique.Issy Long
-
Allow setting the
schema_formatvia database configuration.primary: schema_format: rubyUseful for multi-database setups when apps require different formats per-database.
T S Vallender
-
Support disabling indexes for MySQL v8.0.0+ and MariaDB v10.6.0+
MySQL 8.0.0 added an option to disable indexes from being used by the query optimizer by making them "invisible". This allows the index to still be maintained and updated but no queries will be permitted to use it. This can be useful for adding new invisible indexes or making existing indexes invisible before dropping them to ensure queries are not negatively affected. See https://dev.mysql.com/blog-archive/mysql-8-0-invisible-indexes/ for more details.
MariaDB 10.6.0 also added support for this feature by allowing indexes to be "ignored" in queries. See https://mariadb.com/kb/en/ignored-indexes/ for more details.
Active Record now supports this option for MySQL 8.0.0+ and MariaDB 10.6.0+ for index creation and alteration where the new index option
enabled: true/falsecan be passed to column and index methods as below:add_index :users, :email, enabled: false enable_index :users, :email add_column :users, :dob, :string, index: { enabled: false } change_table :users do |t| t.index :name, enabled: false t.index :dob t.disable_index :dob t.column :username, :string, index: { enabled: false } t.references :account, index: { enabled: false } end create_table :users do |t| t.string :name, index: { enabled: false } t.string :email t.index :email, enabled: false endMerve Taner
-
Respect
implicit_order_columninActiveRecord::Relation#reverse_order.Joshua Young
-
Add column types to
ActiveRecord::Resultfor SQLite3.Andrew Kane
-
Raise
ActiveRecord::ReadOnlyErrorwhen pessimistically locking with a readonly role.Joshua Young
-
Fix using the
SQLite3Adapter'sdbconsolemethod outside of a Rails application.Hartley McGuire
-
Fix migrating multiple databases with
ActiveRecord::PendingMigrationaction.Gannon McGibbon
-
Enable automatically retrying idempotent association queries on connection errors.
Hartley McGuire
-
Add
allow_retrytosql.active_recordinstrumentation.This enables identifying queries which queries are automatically retryable on connection errors.
Hartley McGuire
-
Better support UPDATE with JOIN for Postgresql and SQLite3
Previously when generating update queries with one or more JOIN clauses, Active Record would use a sub query which would prevent to reference the joined tables in the
SETclause, for instance:Comment.joins(:post).update_all("title = posts.title")This is now supported as long as the relation doesn't also use a
LIMIT,ORDERorGROUP BYclause. This was supported by the MySQL adapter for a long time.Jean Boussier
-
Introduce a before-fork hook in
ActiveSupport::Testing::Parallelizationto clear existing connections, to avoid fork-safety issues with the mysql2 adapter.Fixes #41776
Mike Dalessio, Donal McBreen
-
PoolConfig no longer keeps a reference to the connection class.
Keeping a reference to the class caused subtle issues when combined with reloading in development. Fixes #54343.
Mike Dalessio
-
Fix SQL notifications sometimes not sent when using async queries.
Post.async_count ActiveSupport::Notifications.subscribed(->(*) { "Will never reach here" }) do Post.count endIn rare circumstances and under the right race condition, Active Support notifications would no longer be dispatched after using an asynchronous query. This is now fixed.
Edouard Chin
-
Eliminate queries loading dumped schema cache on Postgres
Improve resiliency by avoiding needing to open a database connection to load the type map while defining attribute methods at boot when a schema cache file is configured on PostgreSQL databases.
James Coleman
-
ActiveRecord::Coder::JSONcan be instantiatedOptions can now be passed to
ActiveRecord::Coder::JSONwhen instantiating the coder. This allows:serialize :config, coder: ActiveRecord::Coder::JSON.new(symbolize_names: true)matthaigh27
-
Deprecate using
insert_all/upsert_allwith unpersisted records in associations.Using these methods on associations containing unpersisted records will now show a deprecation warning, as the unpersisted records will be lost after the operation.
Nick Schwaderer
-
Make column name optional for
index_exists?.This aligns well with
remove_indexsignature as well, where index name doesn't need to be derived from the column names.Ali Ismayiliov
-
Change the payload name of
sql.active_recordnotification for eager loading from "SQL" to "#{model.name} Eager Load".zzak
-
Enable automatically retrying idempotent
#exists?queries on connection errors.Hartley McGuire, classidied
-
Deprecate usage of unsupported methods in conjunction with
update_all:update_allwill now print a deprecation message if a query includes eitherWITH,WITH RECURSIVEorDISTINCTstatements. Those were never supported and were ignored when generating the SQL query.An error will be raised in a future Rails release. This behavior will be consistent with
delete_allwhich currently raises an error for unsupported statements.Edouard Chin
-
The table columns inside
schema.rbare now sorted alphabetically.Previously they'd be sorted by creation order, which can cause merge conflicts when two branches modify the same table concurrently.
John Duff
-
Introduce versions formatter for the schema dumper.
It is now possible to override how schema dumper formats versions information inside the
structure.sqlfile. Currently, the versions are simply sorted in the decreasing order. Within large teams, this can potentially cause many merge conflicts near the top of the list.Now, the custom formatter can be provided with a custom sorting logic (e.g. by hash values of the versions), which can greatly reduce the number of conflicts.
fatkodima
-
Serialized attributes can now be marked as comparable.
A not rare issue when working with serialized attributes is that the serialized representation of an object can change over time. Either because you are migrating from one serializer to the other (e.g. YAML to JSON or to msgpack), or because the serializer used subtly changed its output.
One example is libyaml that used to have some extra trailing whitespaces, and recently fixed that. When this sorts of thing happen, you end up with lots of records that report being changed even though they aren't, which in the best case leads to a lot more writes to the database and in the worst case lead to nasty bugs.
The solution is to instead compare the deserialized representation of the object, however Active Record can't assume the deserialized object has a working
==method. Hence why this new functionality is opt-in.serialize :config, type: Hash, coder: JSON, comparable: trueJean Boussier
-
Fix MySQL default functions getting dropped when changing a column's nullability.
Bastian Bartmann
-
SQLite extensions can be configured in
config/database.yml.The database configuration option
extensions:allows an application to load SQLite extensions when usingsqlite3>= v2.4.0. The array members may be filesystem paths or the names of modules that respond to.to_path:development: adapter: sqlite3 extensions: - SQLean::UUID # module name responding to `.to_path` - .sqlpkg/nalgeon/crypto/crypto.so # or a filesystem path - <%= AppExtensions.location %> # or ruby code returning a pathMike Dalessio
-
ActiveRecord::Middleware::ShardSelectorsupports granular database connection switching.A new configuration option,
class_name:, is introduced toconfig.active_record.shard_selectorto allow an application to specify the abstract connection class to be switched by the shard selection middleware. The default class isActiveRecord::Base.For example, this configuration tells
ShardSelectorto switch shards usingAnimalsRecord.connected_to:config.active_record.shard_selector = { class_name: "AnimalsRecord" }Mike Dalessio
-
Reset relations after
insert_all/upsert_all.Bulk insert/upsert methods will now call
resetif used on a relation, matching the behavior ofupdate_all.Milo Winningham
-
Use
_Nas a parallel tests databases suffixesPeviously,
-Nwas used as a suffix. This can cause problems for RDBMSes which do not support dashes in database names.fatkodima
-
Remember when a database connection has recently been verified (for two seconds, by default), to avoid repeated reverifications during a single request.
This should recreate a similar rate of verification as in Rails 7.1, where connections are leased for the duration of a request, and thus only verified once.
Matthew Draper
-
Allow to reset cache counters for multiple records.
Aircraft.reset_counters([1, 2, 3], :wheels_count)It produces much fewer queries compared to the custom implementation using looping over ids. Previously:
O(ids.size * counters.size)queries, now:O(ids.size + counters.size)queries.fatkodima
-
Add
affected_rowstosql.active_recordNotification.Hartley McGuire
-
Fix
sumwhen performing a grouped calculation.User.group(:friendly).sumno longer worked. This is fixed.Edouard Chin
-
Add support for enabling or disabling transactional tests per database.
A test class can now override the default
use_transactional_testssetting for individual databases, which can be useful if some databases need their current state to be accessible to an external process while tests are running.class MostlyTransactionalTest < ActiveSupport::TestCase self.use_transactional_tests = true skip_transactional_tests_for_database :shared endMatthew Cheetham, Morgan Mareve
-
Cast
query_cachevalue when using URL configuration.zzak
-
NULLS NOT DISTINCT works with UNIQUE CONSTRAINT as well as UNIQUE INDEX.
Ryuta Kamizono
-
PG::UnableToSend: no connection to the serveris now retryable as a connection-related exceptionKazuma Watanabe
Action View
-
The BEGIN template annotation/comment was previously printed on the same line as the following element. We now insert a newline inside the comment so it spans two lines without adding visible whitespace to the HTML output to enhance readability.
Before:
<!-- BEGIN /Users/siaw23/Desktop/rails/actionview/test/fixtures/actionpack/test/greeting.html.erb --><p>This is grand!</p>After:
<!-- BEGIN /Users/siaw23/Desktop/rails/actionview/test/fixtures/actionpack/test/greeting.html.erb --><p>This is grand!</p>Emmanuel Hayford
-
Add structured events for Action View:
action_view.render_templateaction_view.render_partialaction_view.render_layoutaction_view.render_collectionaction_view.render_start
Gannon McGibbon
-
Fix label with
foroption not getting prefixed by formnamespacevalueAbeid Ahmed, Hartley McGuire
-
Add
fetchpriorityto Link headers to match HTML generated bypreload_link_tag.Guillermo Iguaran
-
Add CSP
nonceto Link headers generated bypreload_link_tag.Alexander Gitter
-
Allow
current_page?to match against specific HTTP method(s) with amethod:option.Ben Sheldon
-
Remove
autocomplete="off"on hidden inputs generated by the following tags:-
form_tag,token_tag,method_tag
As well as the hidden parameter fields included in
button_to,check_box,select(withmultiple) andfile_fieldforms.nkulway
-
-
Enable configuring the strategy for tracking dependencies between Action View templates.
The existing
:regexstrategy is kept as the default, but withload_defaults 8.1the strategy will be:ruby(using a real Ruby parser).Hartley McGuire
-
Introduce
relative_time_in_wordshelperrelative_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"Matheus Richard
-
Make
nonce: falseremove the nonce attribute fromjavascript_tag,javascript_include_tag, andstylesheet_link_tag.francktrouillez
-
Add
dom_targethelper to createdom_id-like strings from an unlimited number of objects.Ben Sheldon
-
Respect
html_options[:form]whencollection_checkboxesgenerates the hidden<input>.Riccardo Odone
-
Layouts have access to local variables passed to
render.This fixes #31680 which was a regression in Rails 5.1.
Mike Dalessio
-
Argument errors related to strict locals in templates now raise an
ActionView::StrictLocalsError, and all other argument errors are reraised as-is.Previously, any
ArgumentErrorraised during template rendering was swallowed during strict local error handling, so that anArgumentErrorunrelated to strict locals (e.g., a helper method invoked with incorrect arguments) would be replaced by a similarArgumentErrorwith an unrelated backtrace, making it difficult to debug templates.Now, any
ArgumentErrorunrelated to strict locals is reraised, preserving the original backtrace for developers.Also note that
ActionView::StrictLocalsErroris a subclass ofArgumentError, so any existing code that rescuesArgumentErrorwill continue to work.Fixes #52227.
Mike Dalessio
-
Improve error highlighting of multi-line methods in ERB templates or templates where the error occurs within a do-end block.
Martin Emde
-
Fix a crash in ERB template error highlighting when the error occurs on a line in the compiled template that is past the end of the source template.
Martin Emde
-
Improve reliability of ERB template error highlighting. Fix infinite loops and crashes in highlighting and improve tolerance for alternate ERB handlers.
Martin Emde
-
Allow
hidden_fieldandhidden_field_tagto accept a custom autocomplete value.brendon
-
Add a new configuration
content_security_policy_nonce_autofor automatically adding a nonce to the tags affected by the directives specified by thecontent_security_policy_nonce_directivesconfiguration option.francktrouillez
Action Pack
-
Submit test requests using
as: :htmlwithContent-Type: x-www-form-urlencodedSean Doyle
-
Add link-local IP ranges to
ActionDispatch::RemoteIpdefault proxies.Link-local addresses (
169.254.0.0/16for IPv4 andfe80::/10for IPv6) are now included in the default trusted proxy list, similar to private IP ranges.Adam Daniels
-
remote_ipwill no longer ignore IPs in X-Forwarded-For headers if they are accompanied by port information.Duncan Brown, Prevenios Marinos, Masafumi Koba, Adam Daniels
-
Add
action_dispatch.verbose_redirect_logssetting that logs where redirects were called from.Similar to
active_record.verbose_query_logsandactive_job.verbose_enqueue_logs, this adds a line in your logs that shows where a redirect was called from.Example:
Redirected to http://localhost:3000/posts/1 ↳ app/controllers/posts_controller.rb:32:in `block (2 levels) in create'Dennis Paagman
-
Add engine route filtering and better formatting in
bin/rails routes.Allow engine routes to be filterable in the routing inspector, and improve formatting of engine routing output.
Before:
> bin/rails routes -e engine_only No routes were found for this grep pattern. For more information about routes, see the Rails guide: https://guides.rubyonrails.org/routing.html.After:
> bin/rails routes -e engine_only Routes for application: No routes were found for this grep pattern. For more information about routes, see the Rails guide: https://guides.rubyonrails.org/routing.html. Routes for Test::Engine: Prefix Verb URI Pattern Controller#Action engine GET /engine_only(.:format) a#bDennis Paagman, Gannon McGibbon
-
Add structured events for Action Pack and Action Dispatch:
action_dispatch.redirectaction_controller.request_startedaction_controller.request_completedaction_controller.callback_haltedaction_controller.rescue_from_handledaction_controller.file_sentaction_controller.redirectedaction_controller.data_sentaction_controller.unpermitted_parametersaction_controller.fragment_cache
Adrianna Chang
-
URL helpers for engines mounted at the application root handle
SCRIPT_NAMEcorrectly.Fixed an issue where
SCRIPT_NAMEis not applied to paths generated for routes in an engine mounted at "/".Mike Dalessio
-
Update
ActionController::Metal::RateLimitingto support passing method names to:byand:withclass SignupsController < ApplicationController rate_limit to: 10, within: 1.minute, with: :redirect_with_flash private def redirect_with_flash redirect_to root_url, alert: "Too many requests!" end endSean Doyle
-
Optimize
ActionDispatch::Http::URL.build_host_urlwhen protocol is included in host.When using URL helpers with a host that includes the protocol (e.g.,
{ host: "https://example.com" }), skip unnecessary protocol normalization and string duplication since the extracted protocol is already in the correct format. This eliminates 2 string allocations per URL generation and provides a ~10% performance improvement for this case.Joshua Young, Hartley McGuire
-
Allow
action_controller.loggerto be disabled by setting it tonilorfalseinstead of always defaulting toRails.logger.Roberto Miranda
-
Remove deprecated support to a route to multiple paths.
Rafael Mendonça França
-
Remove deprecated support for using semicolons as a query string separator.
Before:
ActionDispatch::QueryParser.each_pair("foo=bar;baz=quux").to_a
=> [["foo", "bar"], ["baz", "quux"]]
```
After:
```ruby
ActionDispatch::QueryParser.each_pair("foo=bar;baz=quux").to_a
=> [["foo", "bar;baz=quux"]]
```
*Rafael Mendonça França*
-
Remove deprecated support to skipping over leading brackets in parameter names in the parameter parser.
Before:
ActionDispatch::ParamBuilder.from_query_string("[foo]=bar") # => { "foo" => "bar" } ActionDispatch::ParamBuilder.from_query_string("[foo][bar]=baz") # => { "foo" => { "bar" => "baz" } }After:
ActionDispatch::ParamBuilder.from_query_string("[foo]=bar") # => { "[foo]" => "bar" } ActionDispatch::ParamBuilder.from_query_string("[foo][bar]=baz") # => { "[foo]" => { "bar" => "baz" } }Rafael Mendonça França
-
Deprecate
Rails.application.config.action_dispatch.ignore_leading_brackets.Rafael Mendonça França
-
Raise
ActionController::TooManyRequestserror fromActionController::RateLimitingRequests that exceed the rate limit raise an
ActionController::TooManyRequestserror. By default, Action Dispatch rescues the error and responds with a429 Too Many Requestsstatus.Sean Doyle
-
Add .md/.markdown as Markdown extensions and add a default
markdown:renderer:class Page def to_markdown body end end class PagesController < ActionController::Base def show @​page = Page.find(params[:id]) respond_to do |format| format.html format.md { render markdown: @​page } end end endDHH
-
Add headers to engine routes inspection command
Petrik de Heus
-
Add "Copy as text" button to error pages
Mikkel Malmberg
-
Add
scope:option torate_limitmethod.Previously, it was not possible to share a rate limit count between several controllers, since the count was by default separate for each controller.
Now, the
scope:option solves this problem.class APIController < ActionController::API rate_limit to: 2, within: 2.seconds, scope: "api" end class API::PostsController < APIController
...
end
class API::UsersController < APIController
...
end
```
*ArthurPV*, *Kamil Hanus*
-
Add support for
rack.response_finishedcallbacks in ActionDispatch::Executor.The executor middleware now supports deferring completion callbacks to later in the request lifecycle by utilizing Rack's
rack.response_finishedmechanism, when available. This enables applications to definerack.response_finishedcallbacks that may rely on state that would be cleaned up by the executor's completion callbacks.Adrianna Chang, Hartley McGuire
-
Produce a log when
rescue_fromis invoked.Steven Webb, Jean Boussier
-
Allow hosts redirects from
hostsRails configurationconfig.action_controller.allowed_redirect_hosts << "example.com"Kevin Robatel
-
rate_limit.action_controllernotification has additional payloadadditional values: count, to, within, by, name, cache_key
Jonathan Rochkind
-
Add JSON support to the built-in health controller.
The health controller now responds to JSON requests with a structured response containing status and timestamp information. This makes it easier for monitoring tools and load balancers to consume health check data programmatically.
/up.json
{
"status": "up",
"timestamp": "2025-09-19T12:00:00Z"
}
```
*Francesco Loreti*, *Juan Vásquez*
-
Allow to open source file with a crash from the browser.
Igor Kasyanchuk
-
Always check query string keys for valid encoding just like values are checked.
Casper Smits
-
Always return empty body for HEAD requests in
PublicExceptionsandDebugExceptions.This is required by
Rack::Lint(per RFC9110).Hartley McGuire
-
Add comprehensive support for HTTP Cache-Control request directives according to RFC 9111.
Provides a
request.cache_control_directivesobject that gives access to request cache directives:
Boolean directives
request.cache_control_directives.only_if_cached? # => true/false
request.cache_control_directives.no_cache? # => true/false
request.cache_control_directives.no_store? # => true/false
request.cache_control_directives.no_transform? # => true/false
Value directives
request.cache_control_directives.max_age # => integer or nil
request.cache_control_directives.max_stale # => integer or nil (or true for valueless max-stale)
request.cache_control_directives.min_fresh # => integer or nil
request.cache_control_directives.stale_if_error # => integer or nil
Special helpers for max-stale
request.cache_control_directives.max_stale? # => true if max-stale present (with or without value)
request.cache_control_directives.max_stale_unlimited? # => true only for valueless max-stale
```
Example usage:
```ruby
def show
if request.cache_control_directives.only_if_cached?
@​article = Article.find_cached(params[:id])
return head(:gateway_timeout) if @​article.nil?
else
@​article = Article.find(params[:id])
end
render :show
end
```
*egg528*
-
Add assert_in_body/assert_not_in_body as the simplest way to check if a piece of text is in the response body.
DHH
-
Include cookie name when calculating maximum allowed size.
Hartley McGuire
-
Implement
must-understanddirective according to RFC 9111.The
must-understanddirective indicates that a cache must understand the semantics of the response status code, or discard the response. This directive is enforced to be used only withno-storeto ensure proper cache behavior.class ArticlesController < ApplicationController def show @​article = Article.find(params[:id]) if @​article.special_format? must_understand render status: 203 # Non-Authoritative Information else fresh_when @​article end end endheka1024
-
The JSON renderer doesn't escape HTML entities or Unicode line separators anymore.
Using
render json:will no longer escape<,>,&,U+2028andU+2029characters that can cause errors when the resulting JSON is embedded in JavaScript, or vulnerabilities when the resulting JSON is embedded in HTML.Since the renderer is used to return a JSON document as
application/json, it's typically not necessary to escape those characters, and it improves performance.Escaping will still occur when the
:callbackoption is set, since the JSON is used as JavaScript code in this situation (JSONP).You can use the
:escapeoption or setconfig.action_controller.escape_json_responsestotrueto restore the escaping behavior.class PostsController < ApplicationController def index render json: Post.last(30), escape: true end endÉtienne Barrié, Jean Boussier
-
Load lazy route sets before inserting test routes
Without loading lazy route sets early, we miss
after_routes_loadedcallbacks, or risk invoking them with the test routes instead of the real ones if another load is triggered by an engine.Gannon McGibbon
-
Raise
AbstractController::DoubleRenderErrorifheadis called after rendering.After this change, invoking
headwill lead to an error if response body is already set:class PostController < ApplicationController def index render locals: {} head :ok end endIaroslav Kurbatov
-
The Cookie Serializer can now serialize an Active Support SafeBuffer when using message pack.
Such code would previously produce an error if an application was using messagepack as its cookie serializer.
class PostController < ApplicationController def index flash.notice = t(:hello_html) # This would try to serialize a SafeBuffer, which was not possible. end endEdouard Chin
-
Fix
Rails.application.reload_routes!from clearing almost all routes.When calling
Rails.application.reload_routes!inside a middleware of a Rake task, it was possible under certain conditions that all routes would be cleared. If ran inside a middleware, this would result in getting a 404 on most page you visit. This issue was only happening in development.Edouard Chin
-
Add resource name to the
ArgumentErrorthat's raised when invalid:onlyor:exceptoptions are given to#resourceor#resourcesThis makes it easier to locate the source of the problem, especially for routes drawn by gems.
Before:
:only and :except must include only [:index, :create, :new, :show, :update, :destroy, :edit], but also included [:foo, :bar]After:
Route `resources :products` - :only and :except must include only [:index, :create, :new, :show, :update, :destroy, :edit], but also included [:foo, :bar]Jeremy Green
-
A route pointing to a non-existing controller now returns a 500 instead of a 404.
A controller not existing isn't a routing error that should result in a 404, but a programming error that should result in a 500 and be reported.
Until recently, this was hard to untangle because of the support for dynamic
:controllersegment in routes, but since this is deprecated and will be removed in Rails 8.1, we can now easily not consider missing controllers as routing errors.Jean Boussier
-
Add
check_collisionsoption toActionDispatch::Session::CacheStore.Newly generated session ids use 128 bits of randomness, which is more than enough to ensure collisions can't happen, but if you need to harden sessions even more, you can enable this option to check in the session store that the id is indeed free you can enable that option. This however incurs an extra write on session creation.
Shia
-
In ExceptionWrapper, match backtrace lines with built templates more often, allowing improved highlighting of errors within do-end blocks in templates. Fix for Ruby 3.4 to match new method labels in backtrace.
Martin Emde
-
Allow setting content type with a symbol of the Mime type.
Before
response.content_type = "text/html"
After
response.content_type = :html
```
*Petrik de Heus*
Active Job
-
Add structured events for Active Job:
active_job.enqueuedactive_job.bulk_enqueuedactive_job.startedactive_job.completedactive_job.retry_scheduledactive_job.retry_stoppedactive_job.discardedactive_job.interruptactive_job.resumeactive_job.step_skippedactive_job.step_startedactive_job.step
Adrianna Chang
-
Deprecate built-in
sidekiqadapter.If you're using this adapter, upgrade to
sidekiq7.3.3 or later to use thesidekiqgem's adapter.fatkodima
-
Remove deprecated internal
SuckerPunchadapter in favor of the adapter included with thesucker_punchgem.Rafael Mendonça França
-
Remove support to set
ActiveJob::Base.enqueue_after_transaction_committo:never,:alwaysand:default.Rafael Mendonça França
-
Remove deprecated
Rails.application.config.active_job.enqueue_after_transaction_commit.Rafael Mendonça França
-
ActiveJob::Serializers::ObjectSerializers#klassmethod is now public.Custom Active Job serializers must have a public
#klassmethod too. The returned class will be index allowing for faster serialization.Jean Boussier
-
Allow jobs to the interrupted and resumed with Continuations
A job can use Continuations by including the
ActiveJob::Continuableconcern. Continuations split jobs into steps. When the queuing system is shutting down jobs can be interrupted and their progress saved.class ProcessImportJob include ActiveJob::Continuable def perform(import_id) @​import = Import.find(import_id)
block format
step :initialize do
@​import.initialize
end
step with cursor, the cursor is saved when the job is interrupted
step :process do |step|
@​import.records.find_each(start: step.cursor) do |record|
record.process
step.advance! from: record.id
end
end
method format
step :finalize
private
def finalize
@​import.finalize
end
end
end
```
*Donal McBreen*
-
Defer invocation of ActiveJob enqueue callbacks until after commit when
enqueue_after_transaction_commitis enabled.Will Roever
-
Add
report:option toActiveJob::Base#retry_onand#discard_onWhen the
report:option is passed, errors will be reported to the error reporter before being retried / discarded.Andrew Novoselac
-
Accept a block for
ActiveJob::ConfiguredJob#perform_later.This was inconsistent with a regular
ActiveJob::Base#perform_later.fatkodima
-
Raise a more specific error during deserialization when a previously serialized job class is now unknown.
ActiveJob::UnknownJobClassErrorwill be raised instead of a more genericNameErrorto make it easily possible for adapters to tell if theNameErrorwas raised during job execution or deserialization.Earlopain
Action Mailer
-
Add structured events for Action Mailer:
action_mailer.deliveredaction_mailer.processed
Gannon McGibbon
-
Add
deliver_all_laterto enqueue multiple emails at once.user_emails = User.all.map { |user| Notifier.welcome(user) } ActionMailer.deliver_all_later(user_emails)
use a custom queue
ActionMailer.deliver_all_later(user_emails, queue: :my_queue)
```
This can greatly reduce the number of round-trips to the queue datastore.
For queue adapters that do not implement the `enqueue_all` method, we
fall back to enqueuing email jobs indvidually.
*fatkodima*
Action Cable
-
Allow passing composite channels to
ActionCable::Channel#stream_for– e.g.stream_for [ group, group.owner ]hey-leon
-
Allow setting nil as subscription connection identifier for Redis.
Nguyen Nguyen
Active Storage
-
Add structured events for Active Storage:
active_storage.service_uploadactive_storage.service_downloadactive_storage.service_streaming_downloadactive_storage.previewactive_storage.service_deleteactive_storage.service_delete_prefixedactive_storage.service_existactive_storage.service_urlactive_storage.service_mirror
Gannon McGibbon
-
Allow analyzers and variant transformer to be fully configurable
ActiveStorage.analyzers can be set to an empty array:
config.active_storage.analyzers = []
=> ActiveStorage.analyzers = []
or use custom analyzer:
config.active_storage.analyzers = [ CustomAnalyzer ]
=> ActiveStorage.analyzers = [ CustomAnalyzer ]
```
If no configuration is provided, it will use the default analyzers.
You can also disable variant processor to remove warnings on startup about missing gems.
```ruby
config.active_storage.variant_processor = :disabled
```
*zzak*, *Alexandre Ruban*
-
Remove deprecated
:azurestorage service.Rafael Mendonça França
-
Remove unnecessary calls to the GCP metadata server.
Calling Google::Auth.get_application_default triggers an explicit call to the metadata server - given it was being called for significant number of file operations, it can lead to considerable tail latencies and even metadata server overloads. Instead, it's preferable (and significantly more efficient) that applications use:
Google::Apis::RequestOptions.default.authorization = Google::Auth.get_application_default(...)In the cases applications do not set that, the GCP libraries automatically determine credentials.
This also enables using credentials other than those of the associated GCP service account like when using impersonation.
Alex Coomans
-
Direct upload progress accounts for server processing time.
Jeremy Daer
-
Delegate
ActiveStorage::Filename#to_strto#to_sSupports checking String equality:
filename = ActiveStorage::Filename.new("file.txt") filename == "file.txt" # => true filename in "file.txt" # => true "file.txt" == filename # => trueSean Doyle
-
A Blob will no longer autosave associated Attachment.
This fixes an issue where a record with an attachment would have its dirty attributes reset, preventing your
after commitcallbacks on that record to behave as expected.Note that this change doesn't require any changes on your application and is supposed to be internal. Active Storage Attachment will continue to be autosaved (through a different relation).
Edouard-chin
Action Mailbox
-
Add
reply_to_addressextension method onMail::Message.Mr0grog
Action Text
-
De-couple
@rails/actiontext/attachment_upload.jsfromTrix.AttachmentImplement
@rails/actiontext/index.jswith adirect-upload:progressevent listeners andPromiseresolution.Sean Doyle
-
Capture block content for form helper methods
<%= rich_textarea_tag :content, nil do %> <h1>hello world</h1> <% end %> <!-- <input type="hidden" name="content" id="trix_input_1" value="<h1>hello world</h1>"/><trix-editor … --> <%= rich_textarea :message, :content, input: "trix_input_1" do %> <h1>hello world</h1> <% end %> <!-- <input type="hidden" name="message[content]" id="trix_input_1" value="<h1>hello world</h1>"/><trix-editor … --> <%= form_with model: Message.new do |form| %> <%= form.rich_textarea :content do %> <h1>hello world</h1> <% end %> <% end %> <!-- <form action="/messages" accept-charset="UTF-8" method="post"><input type="hidden" name="message[content]" id="message_content_trix_input_message" value="<h1>hello world</h1>"/><trix-editor … -->Sean Doyle
-
Generalize
:rich_text_areaCapybara selectorPrepare for more Action Text-capable WYSIWYG editors by making
:rich_text_arearely on the presence of[role="textbox"]and[contenteditable]HTML attributes rather than a<trix-editor>element.Sean Doyle
-
Forward
fill_in_rich_text_areaoptions to Capybarafill_in_rich_textarea "Rich text editor", id: "trix_editor_1", with: "Hello world!"Sean Doyle
-
Attachment upload progress accounts for server processing time.
Jeremy Daer
-
The Trix dependency is now satisfied by a gem,
action_text-trix, rather than vendored files. This allows applications to bump Trix versions independently of Rails releases. Effectively this also upgrades Trix to>= 2.1.15.Mike Dalessio
-
Change
ActionText::RichText#embedsassignment frombefore_savetobefore_validationSean Doyle
Railties
-
Suggest
bin/rails action_text:installfrom Action Dispatch error pageSean Doyle
-
Remove deprecated
STATS_DIRECTORIES.Rafael Mendonça França
-
Remove deprecated
bin/rake statscommand.Rafael Mendonça França
-
Remove deprecated
rails/console/methods.rbfile.Rafael Mendonça França
-
Don't generate system tests by default.
Rails scaffold generator will no longer generate system tests by default. To enable this pass
--system-tests=trueor generate them withbin/rails generate system_test name_of_test.Eileen M. Uchitelle
-
Optionally skip bundler-audit.
Skips adding the
bin/bundler-audit&config/bundler-audit.ymlif the gem is not installed whenbin/rails app:updateruns.Passes an option to
--skip-bundler-auditwhen new apps are generated & adds that same option to the--minimalgenerator flag.Jill Klang
-
Show engine routes in
/rails/info/routesas well.Petrik de Heus
-
Exclude
asset_pathconfiguration from Kamaldeploy.ymlfor API applications.API applications don't serve assets, so the
asset_pathconfiguration indeploy.ymlis not needed and can cause 404 errors on in-flight requests. The asset_path is now only included for regular Rails applications that serve assets.Saiqul Haq
-
Reverted the incorrect default
config.public_file_server.headersconfig.If you created a new application using Rails
8.1.0.beta1, make sure to regenerateconfig/environments/production.rb, or to manually edit theconfig.public_file_server.headersconfiguration to just be:
Cache assets for far-future expiry since they are all digest stamped.
config.public_file_server.headers = { "cache-control" => "public, max-age=#{1.year.to_i}" }
```
*Jean Boussier*
-
Add command
rails credentials:fetch PATHto get the value of a credential from the credentials file.$ bin/rails credentials:fetch kamal_registry.passwordMatthew Nguyen, Jean Boussier
-
Generate static BCrypt password digests in fixtures instead of dynamic ERB expressions.
Previously, fixtures with password digest attributes used
<%= BCrypt::Password.create("secret") %>, which regenerated the hash on each test run. Now generates a static hash with a comment showing how to recreate it.Nate Smith, Cassia Scheffer
-
Broaden the
.gitignoreentry when adding a credentials key to ignore all key files.Greg Molnar
-
Remove unnecessary
ruby-versioninput fromruby/setup-rubyTangRufus
-
Add --reset option to bin/setup which will call db:reset as part of the setup.
DHH
-
Add RuboCop cache restoration to RuboCop job in GitHub Actions workflow templates.
Lovro Bikić
-
Skip generating mailer-related files in authentication generator if the application does not use ActionMailer
Rami Massoud
-
Introduce
bin/cifor running your tests, style checks, and security audits locally or in the cloud.The specific steps are defined by a new DSL in
config/ci.rb.ActiveSupport::ContinuousIntegration.run do step "Setup", "bin/setup --skip-server" step "Style: Ruby", "bin/rubocop" step "Security: Gem audit", "bin/bundler-audit" step "Tests: Rails", "bin/rails test test:system" endOptionally use gh-signoff to set a green MR status - ready for merge.
Jeremy Daer, DHH
-
Generate session controller tests when running the authentication generator.
Jerome Dalbert
-
Add bin/bundler-audit and config/bundler-audit.yml for discovering and managing known security problems with app gems.
DHH
-
Rails no longer generates a
bin/bundlebinstub when creating new applications.The
bin/bundlebinstub used to help activate the right version of bundler. This is no longer necessary as this mechanism is now part of Rubygem itself.Edouard Chin
-
Add a
SessionTestHelpermodule withsign_in_as(user)andsign_outtest helpers when runningrails g authentication. Simplifies authentication in integration tests.Bijan Rahnema
-
Rate limit password resets in authentication generator
This helps mitigate abuse from attackers spamming the password reset form.
Chris Oliver
-
Update
rails new --minimaloptionExtend the
--minimalflag to exclude recently added features:skip_brakeman,skip_ci,skip_docker,skip_kamal,skip_rubocop,skip_solidandskip_thruster.eelcoj
-
Add
application-namemetadata to application layoutThe following metatag will be added to
app/views/layouts/application.html.erb<meta name="application-name" content="Name of Rails Application">Steve Polito
-
Use
secret_key_basefrom ENV or credentials when present locally.When ENV["SECRET_KEY_BASE"] or
Rails.application.credentials.secret_key_baseis set for test or development, it is used for theRails.config.secret_key_base, instead of generating atmp/local_secret.txtfile.Petrik de Heus
-
Introduce
RAILS_MASTER_KEYplaceholder in generated ci.yml filesSteve Polito
-
Colorize the Rails console prompt even on non standard environments.
Lorenzo Zabot
-
Don't enable YJIT in development and test environments
Development and test environments tend to reload code and redefine methods (e.g. mocking), hence YJIT isn't generally faster in these environments.
Ali Ismayilov, Jean Boussier
-
Only include PermissionsPolicy::Middleware if policy is configured.
Petrik de Heus
Guides
-
In the Active Job bug report template set the queue adapter to the test adapter so that
assert_enqueued_withcan pass.Andrew White
-
Ensure all bug report templates set
config.secret_key_baseto avoid generation oftmp/local_secret.txtfiles when running the report template.Andrew White
Configuration
-
If you want to rebase/retry this MR, check this box
This MR has been generated by Renovate Bot.