"title"=>"Deferring jobs enqueueing to after the transaction commit, queries count in rendering logs and more",
"summary"=>"Hi, Wojtek here exploring this week’s changes.",
"content"=>"
Hi, Wojtek here exploring this week’s changes.
\n\nRails World 2024 edition website is now live
\nWith tickets going on sale in April.
Allow to register transaction callbacks outside of a record
\nActiveRecord::Base.transaction now yields an ActiveRecord::Transaction object, which allows to register callbacks on it.
Article.transaction do |transaction|\n article.update(published: true)\n transaction.after_commit do\n PublishNotificationMailer.with(article: article).deliver_later\n end\nend\n
Added ActiveRecord::Base.current_transaction which also allows to register callbacks on it.
\nArticle.current_transaction.after_commit do\n PublishNotificationMailer.with(article: article).deliver_later\nend\n
Add ActiveRecord.after_all_transactions_commit callback.
\n\nUseful for code that may run either inside or outside a transaction and need to perform works after the state changes have been properly peristed.
\ndef publish_article(article)\n article.update(published: true)\n ActiveRecord.after_all_transactions_commit do\n PublishNotificationMailer.with(article: article).deliver_later\n end\nend\n
Automatically delay Active Job enqueues to after commit
\nA common mistake with Active Job is to enqueue jobs from inside a transaction, causing them to potentially be picked and ran by another process, before the transaction is committed, which result in various errors.
Topic.transaction do\n topic = Topic.create\n NewTopicNotificationJob.perform_later(topic)\nend\n
Now Active Job will automatically defer the enqueuing to after the transaction is committed, and drop the job if the transaction is rolled back.
\n\nVarious queue implementations can choose to disable this behavior, and users can disable it, or force it on a per job basis:
\nclass NewTopicNotificationJob < ApplicationJob\n self.enqueue_after_transaction_commit = :never # or :always or :default\nend\n
Add queries count to template rendering instrumentation
\nThere is often a need to quickly see how many SQL queries the current action produced. For example, to quickly check if N+1 was solved or if the caching is working and so the number of queries reduced etc. This can be done manually by inspecting the logs and counting the number of queries, but for largish actions with tens-hundreds of SQL queries this is not a simple task.
# Before\nCompleted 200 OK in 3804ms (Views: 41.0ms | ActiveRecord: 33.5ms | Allocations: 112788)\n# After\nCompleted 200 OK in 3804ms (Views: 41.0ms | ActiveRecord: 33.5ms (2 queries, 1 cached) | Allocations: 112788)\n
Add the ability to ignore counter cache columns while they are backfilling
\nStarting to use counter caches on existing large tables can be troublesome, because the column values must be backfilled separately of the column addition (to not lock the table for too long) and before the use of :counter_cache (otherwise methods like size/any?, which use counter caches internally, can produce incorrect results). People usually use database triggers or callbacks on child associations while backfilling before introducing a counter cache configuration to the association.
Now, to safely backfill the column, while keeping the column updated with child records added/removed, use:
\nclass Comment < ApplicationRecord\n belongs_to :post, counter_cache: { active: false }\nend\n
While the counter cache is not “active”, the methods like size/any? will not use it, but get the results directly from the database. After the counter cache column is backfilled, simply remove the { active: false } part from the counter cache definition, and it will now be used by the mentioned methods.
\n\nRetry Actionable Error when running tests
\nAllow Actionable Errors encountered when running tests to be retried. This feature will only be present on interactive terminals.
Raise named exception when database reports an invalid version
\nWhen the MySQL database returns an invalid version string the ActiveRecord::ActiveRecordError error will now be raised.
Make ActiveSupport::BacktraceCleaner copy filters and silencers on dup and clone
\n Previously the copy would still share the internal silencers and filters array, causing state to leak.
You can view the whole list of changes here.\nWe had 16 contributors to the Rails codebase this past week!
\n\nUntil next time!
\n\nSubscribe to get these updates mailed to you.
","author"=>"Wojtek",
"link"=>"https://rubyonrails.org/2024/4/5/this-week-in-rails",
"published_date"=>Fri, 05 Apr 2024 00:00:00.000000000 UTC +00:00,
"image_url"=>nil,
"feed_url"=>"https://rubyonrails.org/2024/4/5/this-week-in-rails",
"language"=>nil,
"active"=>true,
"ricc_source"=>"feedjira::v1",
"created_at"=>Sat, 06 Apr 2024 20:19:58.534779000 UTC +00:00,
"updated_at"=>Mon, 21 Oct 2024 19:29:25.028501000 UTC +00:00,
"newspaper"=>"Ruby on Rails",
"macro_region"=>"Technology"}