Moving Mountains of Data off S3
In this episode of RECORDABLES, we talk through the final and most nerve-racking part of our cloud exit — moving massive amounts of data out of Amazon S3. Principal Programmer Jeremy Daer shares how we moved billions of files with no downtime. He covers everything from dealing with bandwidth limits and AWS constraints to building custom tooling when off-the-shelf options won’t work.
The conversation gets into the human side of a project like this, including verification, anxiety, and the moment you finally hit delete. You’ll also hear how long it actually takes to move that much data and the tools we used to make it happen seamlessly.
Watch the full video episode on YouTube.
Timestam…
Hello! This past fall, I decided to take some time to work on Git’s documentation. I’ve been thinking about working on open source docs for a long time – usually if I think the documentation for something could be improved, I’ll write a blog post or a zine or something. But this time I wondered: could I instead make a few improvements to the official documentation?
So Marie and I made a few changes to the Git documentation!
a data model for Git
After a while working on the documentation, we noticed that Git uses the terms “object”, “reference”, or “index” in its documentation a lot, but that it didn’t have a great explanation of what those terms mean or how they relate to other core…
#782 — January 8, 2026
Ruby Weekly
Zverok's Guide to Language Changes in Ruby 4.0 — Each year, Victor produces a mammoth roundup of changes introduced in the latest Ruby release (Ruby 4.0, in this case). For a release that doesn’t have a huge amount of changes at the language level, he’s come up with some fantastic examples and this is a must-read, as always.
Victor Shepelev
😱 Rails 7.1 Security Support Ended in '25. Need to Upgrade? — No more security updates for Rails 7.1. Get a free Automated Roadmap in minutes. Know what it takes before you start. Need help executing the plan? Our 🌳…
FastRuby.io | Upgrade…
Becky and I are wrapping up a rewatch of Mad Men this week, and throughout the first several seasons, she'd point out the artwork hanging near the entrance of Peter Campbell's apartment, a screenshot of which I shall now hotlink from Blogger's CDN like it's 1959:

(Of course, Pete Campbell is so classless that in my head canon, Trudy must have picked this out.)
Anyway, every time the giraffes would show up, Becky would snap her fingers and point at the TV like Leo in Once Upon a Time in Hollywood before commenting on how much she loved the piece. We are not art people, and I can take a hint, so I ordered a recreation made by this guy on Etsy and hid it in a closet for a few…
Well, I finally got…
When we design websites for consultancies, one question always comes up: where do most people actually view the site? The answer is clear. Most visitors are on their phones. Whether it’s a potential client checking services between meetings or a business partner reviewing your work on the go, mobile is where that first impression happens. That’s why mobile first design has become essential, not optional.
What Mobile First Design Means
Mobile first design means creating a website for smaller screens before adapting it for larger ones. Instead of shrinking a desktop site down, we start by designing what users truly need on their phones. The goal is to make everything simple, readable, and…
Building modals and sliders previously meant reaching for a Stimulus controller. But what if you could create them without writing any JavaScript at all? Like none, zip, nada, nothing. Something that looks like this:

This article shows how to use the native <dialog> element combined with Attractive.js (a JS-free JS library I published recently) to build modals and sliders that work together with Turbo Frames. No custom JavaScript required. 🤯
As always the code can be found on GitHub.
The basics
The foundation is a single <dialog> element in your layout. Start by adding it to your application.html.erb:
<dialog
id="overlay"
closedby="any"
class="
px-3 py-4 max-w-md w-full
…After we’ve addressed all the deprecation warnings and successfully dual-booted an application, the next step in a Rails upgrade is often the most challenging: fixing the broken build.
At this point, the test suite is red, and our job is to bring it back to green. This phase can feel chaotic, but over the years at FastRuby.io, we’ve developed a process that makes it systematic and (relatively) predictable.
In this post, I’ll break down how we approach this step, what patterns we’ve noticed, and how we debug the trickiest failures.
Our “Fix Broken Build” Process
Attack errors before failures
When a test suite runs, errors (exceptions, missing methods, or crashes) block progress. They…
Automating with Cursor commands
I've been very interested lately in how I can use AI to take care of tasks for me. Here is one use case we've found that has been successful so far.
New post over on the PlanetScale blog.
📄 Weekstart
The curse of productivity is that it's self-perpetuating. Respond to e-mails with lightning speed and you just get more replies. Demonstrate your reliability to others long enough, and they'll just bring you more shit to do. Develop productive routines and habits and—before you know it—your natural disposition will shift towards being done with things and away from actually doing things.
Left unconstrained, optimizing for a productive life can diminish the joys of living. Many of us who opt into the lifestyle of "staying on top of shit" do so, ostensibly, to maximize time for creative work, or for leisure, or for family. That's the spirit with which I first discovered Getting Things Done…

I spent the year in San Francisco, having face-to-face conversations with founders you already follow. Here are the top pieces of advice to take into 2026.
I spent 2025 sitting across from the founders of Sentry, WorkOS, Resend, PlanetScale, Chroma and Mastra in San Francisco. Face-to-face. They've built unicorns, category-defining devtools, and they told me what actually works.
Ruby Can Now Draw Maps — And I Started With Ice Cream
January 7, 2026 How libgd-gis turns Ruby into a real GIS engine For many years, Ruby quietly missed something important. Yes, Ruby is amazing at APIs, data processing, background jobs, and web platforms — but when it came to maps, graphics, and spatial data, Ruby was forced to step aside and let other languages do … Continue reading Ruby Can Now Draw Maps — And I Started With Ice Cream
Typing every prompt with your fingers feels backwards in 2026. We can speak faster than we can type, and it feels more natural. Hold a hotkey, speak, and your OS types it for you. If you care about flow, dictation is the most underrated AI upgrade you can make.
In the Omarchy world, Hyprwhspr is getting a lot of attention after a recent DHH tweet:
I had no idea that local model dictation had gotten this good and this fast! I'm blown away by how good hyprwhspr with Omarchy is just using a base model backed by the CPU. Unbelievably accurate. https://t.co/Jtz3eN84Jf
— DHH (@dhh) January 3, 2026
He’s right: local dictation is shockingly good now. The catch is Hyprwhspr uses Python virtual…
You might have heard about Prism, the new Ruby parser. Perhaps you've heard it's faster, more reliable, and more powerful than what we had before. Or maybe you never took a compilers class and aren't sure about what this actually means.
I'm here to tell you all about it, and how it's changing our lives as Ruby developers. Today, I want to take you from square one to writing your first transpiler.
Interpreters 101
Before we begin our journey, let's start with the basics of how an interpreter works, so we're all on the same page. Interpreting a programming language usually involves three main steps:
- Tokenizing input (a.k.a. lexing): Breaking the input text into a list of meaningful tokens.…
ActiveRecord excels at providing methods that balance convenience and performance. Among the most powerful are delete_all and update_all, which execute bulk operations directly in SQL. However, until recently, they behaved inconsistently when used with certain query methods like limit or distinct.
With the introduction of PR #54231, Rails has unified how these methods validate queries before execution, putting an end to this long-standing inconsistency.
The Problem: Different Rules for Similar Operations
Even though both methods operate on Relations, Rails used to impose different restrictions on each.
For instance, if you tried to use update_all on a query containing a limit or an offs…
current_user is a daily companion in Controllers and Views. However, the moment you need that information inside a Model to validate a business rule, things get tricky. Many developers end up passing the user as a parameter everywhere. But did you know Rails has a native solution for this?
CurrentAttributes is the official bridge to carry context from the Controller to the Model cleanly and safely.
The Problem: Argument Pollution
Imagine a method in your model that checks if a user can edit a record. Currently, it likely needs to receive the user as an argument:
1
2
3
def editable_by?(user)
self.author == user || user.admin?
end
While this works, if you have a call chain (Controller …
Announcing rv clean-install
Originally posted on the Spinel blog.
As part of our quest to build a fast Ruby project tool, we’ve been hard at work on the next step of project management: installing gems. As we’ve learned over the last 15 years of working on Bundler and RubyGems, package managers are really complicated! It’s too much to try to copy all of rbenv, and ruby-build, and RubyGems, and Bundler, all at the same time.
Since we can’t ship everything at once, we spent some time discussing the first project management feature we should add after Ruby versions. Inspired by npm and orogene, we decided to build clean-install. Today, we’re releasing the rv clean-install command as part of rv version 0.4.
So, what is a…
A Ruby Regular Expression Engine
Recently I put some finishing touches on the exreg gem, a pure-Ruby implementation of a Unicode regular expression engine. It supports nearly all of the same functionality as Onigmo, the Ruby regular expression engine, with caveats listed in the README. Importantly however, it uses a Thompson-style NFA virtual machine, meaning it is immune to ReDoS caused by catastrophic backtracking.
Background
Most of the technical background for this can be found in Russ Cox’s excellent series of blog posts entitled Regular Expression Matching Can Be Simple And Fast. In short, traditional backtracking regular expression engines (like Onigmo) can be tricked into taking exponential time on certain…
Set Dependabot to run only specific dependency types
We have a Ruby on Rails project that we are sunsetting and we want to tell Dependabot to only update minor versions of Gems as we don’t want to introduce any potential breaking changes to the project.
We can specify this in the Dependabot configuration file like so:
.github/dependabot.yml
version: 2
updates:
- package-ecosystem: bundler
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10
groups:
security-updates:
applies-to: security-updates
patterns:
- '*'
update-types:
- 'minor'
- 'patch'
version-updates:
applies-to: version-updates
patterns:
- '*'
…This will sit within the groups section.
-
security-updates: tells Dependabot the type of update -
version-updates: tells Dependabot the type of update -
patterns: specifies what Gems to apply this to, I have put'…

Developers don’t need more tools—they need fewer, higher-quality ones. This piece distills research and field evidence into six principles for faster, calmer, trustworthy devtools in 2026.
When it comes to developer tools, the same six principles come up time after time. This post is our field-tested playbook for implementing them in the tools you’ll ship in 2026.
This blog started as how DNS works in Neeto. However wecovered a lot of ground about how DNS actually works.
The Basics of DNS Records
A Domain Name System (DNS) is a hierarchical and decentralized naming system forcomputers and servers connected to the Internet. It essentially translateshuman-readable domain names into machine-readable IP addresses.
What is a Domain Name?
A Domain Name is a unique, human-friendly label used to identify one or more IPaddresses. It's what people type into a web browser to visit a website. Forexample google.com and wikipedia.org are domain names.
Purchasing a New Domain Name
You don't buy a domain name outright. Technically you register the right to useit for a…
Aji and Joël talk all things hackerthons and why taking the time to have a little having fun with your work every now and then is important for developers.
Our hosts reflect on their shared experience at a previous RailsConf where they entered a mini hackerthon, why playing around in a creative sandbox is crucial to honing your skills as a dev, and how programming on the fly can teach you a lot about your own strengths and weaknesses.
—
Read more about Joël’s entry in Rails Rumble, as well as their participation in the RailsConf 2022 mini Hackerthon.
Thanks to our sponsors for this episode Judoscale - Autoscale the Right Way (check the link for your free gift!), and Scout…
Your hosts for this…
Year in Books 2025
I got back into a regular reading habit after few years. Here are the books I read:
Happy New Year to the Ruby Community and wishing you all a safe and gentler 2026.
December 2025 README
In case it was missed, we released our December 2025 README Newsletter at the end of the year. It includes highlights from our 2022–2024 Annual Report, Ruby 4.0’s launch (and a lovely message from Matz), new local regionals, and more. You can view the newsletter here.
Annual Report
Included in the latest README, we've included information about our Annual Report release.
This Annual Report covers 2022–2024 and has been in the works since early 2024. Our goal is straightforward: put three years of work, funding, and decisions in one place so the community can see what Ruby Central has actually…
January 5, 2026 How ruby-libgd brings a real raster engine back to Ruby For many years, Ruby quietly lost something fundamental: The ability to generate images natively, fast, and with full control. Yes, RMagick and MiniMagick exist. But they depend on external binaries, are slow, fragile in production, and unsuitable for things like: map tile … Continue reading Ruby Can Create Images Again
Modern Node.js apps often need to perform background jobs. Offloading to a job queue is a great way to preserve web performance when faced with sections of code that are too slow or resource-intensive to handle during an HTTP request. If your app needs to send emails, generate PDFs, process images, or aggregate data, you probably need background jobs.
Offloading these jobs (sometimes called tasks) to a job queue ensures your web process remains responsive and keeps latency down. A typical setup is to have your web processes enqueue jobs to an external system, and one or more worker processes consume and execute those jobs asynchronously.
This works well for keeping your…
One of my main interests with mruby is its ability to create standalone executables. As explored in this post, this is absolutely possible and works well. However, there is a classic issue of most standalone binaries: they can only be run on the same, or very similar, system as the one they were built on.
For example, if I take an executable from my mruby Hello World project, built on amd64 Linux, it won’t work on Silicon Mac:
$ ./hello
exec: Failed to execute process: './hello' the file could not be run by the operating system.
exec: Maybe the interpreter directive (#! line) is broken?
Mruby does have some cross-compilation capabilities, but I’ll be honest: it always felt intimidating,…
Live Countdowns Without JavaScript: Turbo Streams + relative_time_in_words
Self Hosted App
Big Tech Exit
At 39c3, Marc-Uwe Kling, together with the CCC, called for the Digital Independence Day: The idea is to use the first Sunday every month to reduce your personal dependence on big tech and billionaires.
What I like about this approach is that it acknowledges that this is a process of many tiny steps and that a lot of people will need support. Hackerspaces in Germany will offer help to those who require it. I also really liked the idea of the “plus one rule”. Let’s take the example of WhatsApp, the quasi-standard messenger in Germany. Instead of telling people to uninstall WhatsApp, which they will likely be unable to do, ask them to add Signal. This starts a network effect for Signal,…
Happy new year! I started the year by finishing most of our new automated release machinery: check out Release Machine. There’s not a lot to it, but it’s exactly what we need for the future: a signed push triggers release publishing using RubyGems.org trusted publishing (no more credential sharing!), configuration to allow specific sets of releasers per-gem (this is new!), automatic parsing of
CHANGELOG.mdfiles (using Andrew’s new changelog-parser gem, just in time!) creation of GitHub release entries, even publishing of releases to our forum (also new!), which will also come into our Discord thanks to our forum feed.
All that’s left is to sweep through the Dry gems to make sure their…
✉️ 100% Oyster Meat
This is a copy of the Searls of Wisdom newsletter delivered to subscribers on January 1, 2026.
As promised last month, this issue is just oyster meat. It's a new year and as good a time as any to hit reset and get this monthly newsletter back on its preordained beginning-of-the-month-ish delivery cadence. That makes this a quick turnaround after our last issue, so there's not much new to report. Good thing I asked you all to lower your expectations!
Let's see, since we last corresponded:
- Mike McQuaid wrote that he's joined the POSSE Party, so I pulled a quote and recruited him to help deal with maintenance and triage. Another early adopter posted an architectural review of my…
- I spent a few afternoons tweaking a ChatGPT-powered Shortcut for Japanese…
In 2025 I followed the direction many people headed in and switched my version manager to mise-en-place. It has been going really well for me, but recently I came across a problem which took me a bit to figure out (and few very frustrating conversations with LLM, which did not lead to anything). I wanted to test some code with unreleased version 1.20 of Elixir, straight from git.
How to do it? It’s really simple in retrospect. Here are the steps:
1. Build Elixir
$ git clone https://github.com/elixir-lang/elixir.git
$ cd elixir
$ make
Verify it’s built correctly:
$ bin/elixir --version
> Elixir 1.20.0-dev (88cbabf) (compiled with Erlang/OTP 28)
2. Link it in mise
mise link…My most-used display has been Vision Pro ever since it launched in February 2024, but it's been used exclusively as a Mac Virtual Display. This is not only because the Mac is a real computer and visionOS is an IMAX-sized iPad, but because its software keyboard is worse than the worst iPhone keyboard to ever be released. And while I'd be happy to pack a travel keyboard, Vision Pro is already too bulky to fit in my bag. As a result, I may as well lug a real computer around with me and just use Vision Pro as a dumb display.
My second most-used display is an iPad mini, which essentially replaces my iPhone when I'm at home. It's set up to be more book-like: an iPhone stripped of any way to…
Problem: I have hundreds of pages of PDF catalogs in Japanese and no great way to translate them while retaining visual anchors. I like how Safari's built-in translate tool handles images, but it doesn't support PDFs
Solution: point Codex CLI at the directory of PDFs, tell it to rasterize every page of every doc into high-resolution images, then throw together a local webapp to navigate documents and pages. Now I can toggle Safari's built-in translation wherever I want.
Result: I'm no longer worried the curtains won't match the drapes. 💁♂️
This is the golden age of custom software if you've got an ounce of creativity in your bones.
Rebuilding Ruby’s Image Processing Layer: Why ruby-libgd Matters for GIS and the Future of Ruby
Ruby on Rails Developer | Ruby, Backend January 2, 2026 In late 2025, during a RubyConf presentation about disaster-response systems, an uncomfortable truth was stated publicly: Generating map tiles and images on the server is difficult in Ruby. RMagick and MiniMagick were too slow. ruby-gd is used, but it is poorly maintained. This was not … Continue reading Rebuilding Ruby’s Image Processing Layer: Why ruby-libgd Matters for GIS and the Future of Ruby
Black Box Hosting vs. Glass Box Hosting: An Interview With Judoscale's Adam
Greetings, Judoscale readers! While we usually write our posts as a team, I (Jon) wanted to take a novel approach this time around. I wanted to interview Adam, Judoscale’s founder and still the head of our tiny team, to get his outlook on the marketplace of hosting as we begin 2026.
The goal here wasn’t to host a cage match between the various PaaS vendors currently on the market. It was to setup a scenario:
Let’s frame this conversation as a thought experiment: if you were starting a new startup today — something like Judoscale, but fresh — would you still choose Heroku? We’ll look at that decision through the lens of a founder building a real business, not a hobby app — meaning…
RSpec Satisfy Matcher
I've recently discovered (or at least found a good use case for it) the satisfy matcher in RSpec.
My intention was to ensure an attribute contained a string and not another string (within have_attributes).
I tried a few variations of the code below, but none of them worked:
message = Message.first
expect(message).to have_attributes(
conversation_id: conversation.id,
customer: "customer@example.com",
response: include("Hello, world!").and(not_to(include("Subject:")))
)
While inspecting rspec-expectations's source code in search of an exclude matcher or something similar, the satisfy matcher stood out as a good fit:
expect(message).to have_attributes(
conversation_id: conversation…Remote Ruby Wrapped
In this episode of Remote Ruby, Chris, Andrew, and David humorously discuss the rapid increase of 'wrapped' features in various apps, recount personal experiences with food apps, and then dive into their favorite conference moments of the year. They also explore the concept of UI affordances and its importance in web design and give a preview of upcoming conferences in 2026, and a brief discussion on modern CSS and JavaScript elements. Hit download now to hear much more!
Links
Rails 8.1 introduces support for joins in update_all for Postgresql and SQLite.
ActiveRecord joins is used to combine records from multiple tables based on associations,
generating an SQL INNER JOIN.
With update_all, we can update multiple records quickly without triggering model validations, callbacks, or modifying timestamps.
Combining these two methods is useful when we need to perform bulk updates based on data from associated tables. For example, syncing a column value from a parent record to all its children in a single query.
Before
When we use update_all together with joins,
Rails generates a subquery that prevents referencing joined tables in the SET clause,
which results in an ActiveRecord::StatementInvalid error.
For example:
class Client < Application…Hi, it’s zzak. Hope everyone had a great holiday season and a happy new year! 🎊
Let’s explore this week’s changes in the Rails codebase.
Add Rails.app.revision
Add Rails.app.revision to provide a version identifier for error reporting, monitoring, cache keys, etc.
Add ActionDispatch::Request#bearer_token
Add ActionDispatch::Request#bearer_token to extract the bearer token from the Authorization header. Bearer tokens are commonly used for API and MCP requests.
Allow Rails.app.creds to access .env values in dev
In addition to ENV and the encrypted file, Rails.app.creds can now access values from .env files in development mode.
Fixed bin/rails notes command to work with CSS comments
This…
Pixoo64 Ruby Client
I bought a Pixoo64 LED Display to play around with, and I love it! It connects to WiFi and has an on-board HTTP API so you can program it. I made a Ruby client for it that even includes code to convert PNG files to the binary format the sign wants.
One cool thing is that the display can be configured to fetch data from a remote server, so I configured mine to fetch PM2.5 and CO2 data for my office.
Here’s what it’s looking like so far:
Yes, this is how I discovered I need to open a window 😂
Building HTML UI forced me to figure out how to write reusable CSS classes that play nice with Tailwind. Along the way, I looked at how other libraries tackle this. Spoiler: most of them get it wrong.
Let me show you two approaches I found, then I’ll show you what I landed on.
Here’s how Basecoat defines a badge:
@layer components {
.badge,
.badge-primary,
.badge-secondary,
.badge-destructive,
.badge-outline {
@apply inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]…Year in Review 2025
House moves, robot armies, and scratching itches.
January—February
Ten years ago, I was looking at the prices of T-shirt printing machines and figuring out the best way to manage stock and postal services. I’ve always wanted to have a place to exercise my design eye and this year I launched Ruby T-shirts.
I use a mix of Shopify and Printful and add designs whenever they come to me. I don’t have the headspace to manage stock and posting things myself, so this setup “just” (read mostly) works. From a financial perspective it just about breaks even: I’ve had over 100 orders this year and the relatively low cost cost of running a Shopify store combined with the low margins means it’s…
Zoé
While 2022 was all about joins, this year we made a whole new record.
Her name is Zoé and she’s wonderful. I can’t wait for her to meet the world in spite of its flaws.
Along the way, Zoé helped me refocus on what really matters:
- getting lost in that afternoon shine
- holding hands (or fingers)
- ~naps~
- the percussive pleasure of deep farts 💨
- improvising harmonies to soothing songs
- watching sunrises and sunsets like movie premieres
- singing and walking (at the same time)
- feelings within & without
- blissful abandon
Merci Zouzou et à demain matin ☺️

Favorite books of 2025
35 books, 17,000 pages. That fell short of the 50 books target I set for myself, but there were quite a few great books in there. Most of my “reading” this year was through audiobooks, so I ended up listening to 240 hours (that’s 10 whole days!) worth of books.
Non fiction
A Random Walk Down Wall Street (Burton G Malkiel)
Malkiel is one of the earliest advocates for index funds, so a lot of today’s personal finance wisdom comes from this book. Originally written in the 1970s, but regularly updated, it has remained relevant through half a century. He also weaves the narrative much better than most personal finance writers, so it is a delightfully engaging read. He can easily jump from the…
Becky gave me a $100 gift card to Steam for Christmas, so for the first time in a decade I endeavored to hunt for some hidden gems in the Steam Winter Sale. I haven't even booted it up yet, but this trailer immediately convinced me to instabuy Ball x Pit.
I'm sure the game is great, but I wish more trailers were this stupid and irreverent. Gaming is a silly hobby and the best favorite game marketing isn't afraid to embrace that fact.
Becky gave me a $100 gift card to Steam for Christmas, so for the first time in a decade I endeavored to hunt for some hidden gems in the Steam Winter Sale. I haven't even booted it up yet, but this trailer immediately convinced me to instabuy Ball x Pit.
I'm sure the game is great, but I wish more trailers were this stupid and irreverent. Gaming is a silly hobby and the best favorite game marketing isn't afraid to embrace that fact.
2025 in review
On September 23rd, 2025, in a Berlin hospital room, I became a dad. Emma Elanor Margheim entered the world and promptly rearranged every priority I thought I had.
She’s currently asleep, so let me tell you about the rest of the year.
Becoming a Family
The year began with a milestone: on January 13th, Geniya became a German citizen. After oodles of paperwork and appointments and waiting, she walked out of the Ausländerbehörde as a dual citizen. We celebrated with sushi.
By spring, we knew Emma was on the way. In June, we escaped to Südtirol for a babymoon—a last hurrah of lazy mornings and mountain views before our family of 2 become a family of 3. We hiked (more like…
Why Report-Driven Analytics Fail: The Case for Real-Time Analytics for Investment Platforms
Why Independence Matters More Than Scale in Investment Software Architecture
Adding multi-tenancy to a DDD Rails app
Many businesses when they set out to create some software they need, don’t know that one day, they might need multi-tenancy.
This is one of the features, that is not easy for programmers to add later easily. It might take months or even years.
Let me describe how I approached this in an ecommerce app. Essentially, the idea is to allow to create multiple stores, where previously it was one (or actually lack of any, all resources were global).
The ecommerce project
The project I am talking about is called ecommerce and it is part of the RailsEventStore (RES) organization on github. It started as a sample application for RES but over the last 10…
Cat Pics



Did a few cat pics tonight!
GHSA-g9jg-w8vm-g96v (action_text-trix): Trix has a stored XSS vulnerability through its attachment attribute
Direct link to podcast audio file
During the end-of-year podcasting doldrums, I'm pleased to bring you this Feature Release, in which I eschew my tradition of eschewing traditions and present a second annual sorting of the puns. As 2025 (a.k.a. Season 2) of Breaking Change comes to a close, Aaron Patterson once again joins the show to execute our latest iteration of the punsort algorithm.
Following along at home? Here's a spoiler-free link to the original Season 2 rankings.
Ready to be spoiled? Visit /puns for the final pun rankings of 2025.
If you agree, disagree, or are indifferent about where things landed, feel free to get it off your chest at podcast@searls.co.

Two days ago, Rails added a new feature that makes working with bearer tokens easier. Before, you had to parse the Authorization header to extract them. Now, there's a dedicated bearer_token method on the request object that handles this for you.
When building APIs that use bearer token authentication (OAuth 2.0 and JWT-based authentication), you typically receive tokens from the client in the Authorization header…
When we are running Rails migrations, it’s common to combine multiple changes into a single change_table block especially when we want to keep database schema in sync.
Before Rails 7.1
Previously,
validate_constraint and
validate_check_constraint
had to be called outside the change_table block,
requiring constraint creation and
validation to be handled as two separate steps.
For example:
class AddNameColumnsAndConstraintToUser < ActiveRecord::Migration[7.0]
def change
change_table :user, bulk: true do |t|
t.string :first_name
t.string :last_name
t.check_constraint "first_name IS NOT NULL AND last_name IS NOT NULL",
name: "name_not_null", validate: false
…
After
With the enhancement introduced in Rails 7.1,
we can now create cleaner migrations by combining column additions and
constraint validations within a single change_table…
def validate_constr…487: ActiveModel custom attributes
Joël contributes some thoughts on working with custom attributes as he follows up on last week’s discussion about ActiveModels with Sally.
Joël breaks down how he transforms various strings and objects when working with ActiveModels to simplify more advance workloads, as Sally queries their different use cases and how best to utilise them for her own workflow.
—
If you’d like to give some of the gems mentioned in this episode a try for yourself they can be found here - phonelib - money-rails - astronoby
Thanks to our sponsors for this episode Judoscale - Autoscale the Right…
Can Bundler Be as Fast as uv?
At RailsWorld earlier this year, I got nerd sniped by someone. They asked “why can’t Bundler be as fast as uv?” Immediately my inner voice said “YA, WHY CAN’T IT BE AS FAST AS UV????”
My inner voice likes to shout at me, especially when someone asks a question so obvious I should have thought of it myself. Since then I’ve been thinking about and investigating this problem, going so far as to give a presentation at XO Ruby Portland about Bundler performance. I firmly believe the answer is “Bundler can be as fast as uv” (where “as fast” has a margin of error lol).
Fortunately, Andrew Nesbitt recently wrote a post called “How uv got so fast”, and I thought I would take this opportunity to…
schema.rb documents the database structure in a database-agnostic way, providing a Ruby representation of the schema within the limits of what Active Record can express.
Before
When running migrations, Rails generates the schema.rb file by dumping the current database structure. However, the order of columns in schema.rb reflects the physical column order in the database, which typically follows migration history.
Imagine you have a posts table:
create_table "posts", force: :cascade do |t|
t.string "title"
t.boolean "published"
t.text "summary"
end
After applying different migrations, the order of columns may differ on other machines:
create_table "posts", force: :cascade do |t|…#781 — December 29, 2025
Ruby Weekly
Ruby 4.0.0 Released — Yui Naruse of the core team took the helm for this year’s big, and extra special, Ruby release post where we celebrate 30 years of Ruby with the big v4.0! We’re listing a few of the most notable updates below, but it’s worth checking out the post, if only to enjoy the Ruby blog’s new theme.
Yui Naruse
A New Design for the Official Ruby Site — Unveiled a few days before v4.0, Ruby’s official web site has received more than a lick of paint, with a complete, modern redesign. It’s really well put together and gives off more of Ruby’s…
…
If you look closely, you'll spot that the Instagram algorithm has successfully identified my absolute number-one-with-a-bullet favorite topic. How on earth did it figure that out? My phone must be listening to me.
How RIZAP Technologies Turns Junior Developers Into Senior Ruby Engineers
How RIZAP Technologies Turns Junior Developers Into Senior Ruby Engineers December 29, 2025 At RubyWorld Conference 2025 and Kaigi on Rails 2025, a talk by Tomohiro Umeda from RIZAP Technologies quietly delivered one of the most important messages for the future of Ruby engineering. Most companies would love to hire senior engineers. But in reality … Continue reading How RIZAP Technologies Turns Junior Developers Into Senior Ruby Engineers
Continuations 2025/52: Do what you love
Happy holidays, and happy last week of the year!
If you haven’t yet, now is a great time to check our State of Hanami, December 2025, which I posted earlier this week. It’s a great snapshot of everything we achieved this year, and it ends with some of our goals for the year to come.I wasn’t sure if I’d end up writing one of these this week, since I’ve been off enjoying some family time by the coast. They say to do what you love while on holiday, so I’ve read a novella (Slow Bullets by Alastair Reynolds), done some retro gaming (The Legend of Zelda: The Minish Cap on my recently-acquired RG40XXV), done some beach swimming, and as it turns out, a bunch of Ruby open source. So here we are,…
After Ruby…
After a decade under Pablo Cantero's stewardship, Shoryuken has a new maintainer - me. I'm grateful for his graceful handoff of this Ruby SQS library, and I'm picking up where he left off: v7.0.0.rc1 is out now, with the stable release close behind.
What's in v7.0.0
This release modernizes the codebase substantially. It brings several improvements including:
-
Rails 8.1+ features:
- ActiveJob Continuations let jobs checkpoint progress during shutdown and resume after restart.
- Bulk enqueuing via
enqueue_allnow uses SQS batch API. -
CurrentAttributesautomatically flow from enqueue to execution.
-
Dependency reduction:
-
myumura removed
concurrent-rubyentirely, replacing it with pure Ruby… - Co…
-
myumura removed
📸 Doordash Couture
Who is this for? STEM majors realizing they're better off running Uber Eats?
[8/4] How a Scotsman saved hours of my time by turning an LLM into my virtual assistant
![[8/4] How a Scotsman saved hours of my time by turning an LLM into my virtual assistant](https://digitalpress.fra1.cdn.digitaloceanspaces.com/xhtzjbw/2025/12/ChatGPT-Image-Dec-27--2025--05_51_01-AM.png)
Sometimes you get stuck thinking about less-than-ideal solutions, missing the big green elephant staring right at you. I had a nice win in a short time that I didn't want to leave unshared.
I had used a bookkeeping app for several years to file my taxes. Once I decided to switch accountants, I found that this application isn't very interested in you leaving, so it doesn't offer an "export all functionality" option. (a black-hat churn buster right there for you SaaS builders!)
Here are a couple of these screens:
![[8/4] How a Scotsman saved hours of my time by turning an LLM into my virtual assistant](https://digitalpress.fra1.cdn.digitaloceanspaces.com/xhtzjbw/2025/10/Screenshot-2025-10-26-at-10.25.22.png)
![[8/4] How a Scotsman saved hours of my time by turning an LLM into my virtual assistant](https://digitalpress.fra1.cdn.digitaloceanspaces.com/xhtzjbw/2025/10/Screenshot-2025-10-26-at-10.26.09.png)
Basically, I stood before a gigantic mechanical task: clicking through dozens of pages and downloading hundreds of invoices I had uploaded manually for the past years.
My first thought…
A Ruby YAML parser
Recently I built the psych-pure gem, a pure-Ruby implementation of a YAML 1.2 parser and emitter. It fully conforms to the YAML 1.2 specification, passes the entire YAML test suite, and allows you to preserve comments when loading and dumping YAML documents. This post explains how and why.
Motivation
First, let’s talk about YAML. YAML is a surprisingly complex data serialization format. It supports a wide variety of data types and syntactic structures, making it both powerful and a huge pain to implement correctly. If you check out matrix.yaml.info you’ll see that very few of the YAML parsers in use fully conform to the YAML 1.2 spec.
Notably, the one used by Ruby — libyaml — errors out…
Happy Holidays, this is Claudio, Emmanuel, Greg, Vipul, Wojciech, and Zzak, bringing you the summary of what happened with Rails in the past year. It was a busy year with close to 2700 commits from 430 contributors and 14 releases, including Rails 8.1! The Rails Foundation also released a wrap up of 2025, and here are the most noteworthy changes landed in Rails this year.
Fix inconsistency between “delete_all” & “update_all” allowed methods
After this change, trying to call update_all with distinct or a CTE (with, with_recursive) is deprecated and will raise an error in Rails 8.2. This is consistent with the behavior of delete_all.
Ruby Upgrades & RAM Shortages
Chris, Andrew, and David are back together, and the conversation starts out with TV talk, Fallout hype, why some shows overstay their welcome (Prison Break), and the “season one magic” problem (Reacher). Then there’s a big shoutout to Marco’s Rails Luminary win, and a deep dive into AI rabbit holes: self-hosting LLMs, Mac minis, and the looming reality of both token costs and RAM shortages. They discuss the Ruby releases (3.4.8 + Ruby 4.0 preview3), highlighting practical fixes, previewing features like Ruby:: Box, new syntax tweaks, and core classes updates they’re excited about. Hit download now!
Links
Rails 6 is a major milestone that modernizes Rails for the 2020s. The biggest change? Zeitwerk autoloader replaces the classic autoloader, requiring careful attention to file naming conventions.
Plus: Webpacker as default, multiple database support, parallel testing, Action Mailbox, and Action Text.
Note: This is Part 3 of our Rails Upgrade Series. Read Part 1: Planning and Part 2: Rails 4.2 to 5 first.
Before We Start
Expected Timeline: 2-4 weeks for medium sized applications
Medium-sized application: 20,000-50,000 lines of code, 30-100 models, moderate test coverage, 2-5 developers. Smaller apps may take 1-2 weeks, larger enterprise apps 6-12 weeks.
Prerequisites:
- Current…
Ruby 4.0
Highlights:
Note: As Ruby doesn’t follow SemVer, the 4.0 version marks not some significant change/set of changes, but was chosen by Matz to celebrate Ruby’s 30s birthday.
- Support for line breaks before logical operators
-
Setreimplemented efficiently -
Pathnamebecame a core class Ruby::Box-
Ractor: ports
What's New in RubyGems/Bundler 4
Ruby 4.0.0 was released on December 25, 2025, and RubyGems/Bundler 4.0.3 is now bundled with Ruby 4.0.0.
Since my previous post focused on migration and compatibility concerns, I’d like to highlight some of the exciting new features in this release.
Parallelization of C-extension Gem Builds
Add MAKEFLAGS=-j by default before compiling
When installing gems with C extensions (such as mysql2 or pg), RubyGems now automatically adds MAKEFLAGS=-j to the make command for parallel execution. Users previously had to manually configure this themselves. By leveraging multi-core CPUs by default, installation times are significantly reduced.
By default, RubyGems uses Etc.nprocessors + 1, fully…
Why have lower bounds on generics?
Merry Christmas! I made a little present for any of my fellow Japanese learners out there. 🎁
Today I'm pleased to share this ChatGPT-powered Shortcut for Apple platforms I've been working on with you.
Here are its headlining features of the Ingest Japanese shortcut:
-
Render Furigana - ChatGPT tokenizes words and produces readings for kanji and okurigana, which are then assembled into an HTML page with proper
<ruby>and<rt>tags (copyable as an HTML file) - Show Kana Reading - ChatGPT tokenizes the words and converts them their kana pronunciations, separating each word with a space, so you can understand word boundaries at a glance
- Translate to English - Uses whatever additional context has…
It also exposes these utilities:
- Copy Input - copy whatever input…
Ruby 4.0.0
Happy Holidays! ❄️☃️❄️
Ruby 4.0.0 is here along with several enhancements over last year’s Ruby 3.4.0 release. The following highlights the changes in this release. Definitely dig into the release notes for complete details.
Array
Array gains two new methods:
-
#find: Provides an efficient implementation overEnumerable#find(what was previously used). -
#rfind: Allows you to find the last element matching a specific condition which provides a performance improvement overArray#reverse_each.findby avoiding array allocation when messagingEnumerable…
[1, 2, 3].rfind(&:even?) # 2
Binding
Methods such as local_variables, local_variable_get, and local_variable_set no longer handle numbered parameters.
Created by Yukihiro “Matz” Matsumoto and first released in 1995, Ruby arrived with a purpose that was simple but profound: to make coding more human, more intuitive, and more enjoyable. Its object-oriented model, dynamic typing, and elegant syntax offered a fresh alternative to the heavier and more complex languages of that era.
As Ruby marks its 30th anniversary alongside the release of Ruby 4.0, we on the RubyMine team want to reflect on the path that led the language to where it is today and honor this remarkable milestone.
This year, with Ruby turning 30, we’re making RubyMine free for non-commercial use, helping nurture the next generation of Ruby developers and supporting a…
Click here to try Ruby 4.0 in…
It’s (for a few in this world) Christmas day. And also, again for a bit more than a few, the end of 2025. That means things slow down and thus a perfect opportunity to read up on what was happening and published on Rails Designer. Last year I also published a “best of” list (for 2024). And looking at it, things have not slowed down much. Next to Rails Designer’s UI Components Library being steady (about ~1.2k total in 2025), I also published a few new OSS projects (some on this list will be officially launched next year; so you read about them first here; unless you read my newsletter—those were truly the first! 🤫).
- Courrier is one I am really happy about (and use in all my projects)…
Ruby 4.0.0 Released
We are pleased to announce the release of Ruby 4.0.0. Ruby 4.0 introduces “Ruby Box” and “ZJIT”, and adds many improvements.
Ruby Box
Ruby Box is a new (experimental) feature to provide separation about definitions. Ruby Box is enabled when an environment variable RUBY_BOX=1 is specified. The class is Ruby::Box.
Definitions loaded in a box are isolated in the box. Ruby Box can isolate/separate monkey patches, changes of global/class variables, class/module definitions, and loaded native/ruby libraries from other boxes.
Expected use cases are:
- Run test cases in box to protect other tests when the test case uses monkey patches to override something
- Run web app boxes in parallel to…
India after Gandhi
My first and longest read of 2025.
What Is New In Ruby 4.0
Ruby 4.0 is here, releasing on Christmas Day 2025, marking 30 years since Ruby’s first public release. This release packs some genuinely exciting features.
Let’s explore the most impactful changes in Ruby 4.0.
ZJIT - A New JIT Compiler
Ruby 4.0 introduces ZJIT, a new just in time compiler built by the same team behind YJIT. Unlike YJIT’s lazy basic block versioning approach, ZJIT uses a more traditional method based compilation strategy.
The key difference? ZJIT is designed to be more accessible to contributors. It follows a “textbook” compiler architecture that’s easier to understand and modify.
To enable ZJIT, we can use the --zjit flag:
ruby --zjit my_script.rb
While ZJIT is…
I'm working on an inadvisably complex Apple Shortcuts widget for studying Japanese language, and just realized two things that may save you some time in the future:
- If statements are expressions: the value of the "If Result" is available and evaluates to the final value of whatever branch was traveled at runtime
- Repeat blocks may say "each" but actually double as map functions: they return a "Repeat Results" value, which evaluates to a List of the final value of each iteration
Because Shortcuts exposes such a gobsmackingly-frustrating UI for actually building programs, it's easy to assume that you're hobbled by the conventions of something like BASIC, but there are some surprisingly…
So many, many times this past year, I’ve thought to myself, ‘Holy cow, things are moving so fast.’ This is as true in the wider tech world, as it is in the Ruby community. These are exciting times.
Ruby 4.0.0 is days away, the Ruby website and documentation just got awesome new rebrands, and there are constant updates to the Rails framework.
But we’ve also watched this year as companies built on Rails grow and adapt to a new (and constantly shifting) AI landscape in fascinating ways. There are new startups choosing Rails every day, new projects and gems taking shape, new folks joining the community, new conversations, new collaborations, new books being published, new events popping up…
Running Ruby 4 with Ruby::BOX inside Docker (Alpine)
Ruby 4 with Ruby::BOX December 24, 2025 Ruby 4 introduces one of the most important runtime features in the history of the language: Ruby::BOX. It allows Ruby to execute multiple isolated class worlds inside the same process, finally making it possible to load conflicting libraries, plugins, and user code safely. In this guide we will … Continue reading Running Ruby 4 with Ruby::BOX inside Docker (Alpine)
We dig into Valentino’s experimental Ruby gem, agentic, and talk about plan-and-execute workflows, self-assembling agents, and how modern LLMs are reshaping everything from local development to production systems. Along the way, we zoom out to ask bigger questions about learning, career longevity, and what Ruby developers should really be focusing on as AI continues to accelerate.
AI isn’t eliminating the…
A New Look for Ruby's Documentation
Following the ruby-lang.org redesign, we have more news to celebrate Ruby’s 30th anniversary: docs.ruby-lang.org has a completely new look with Aliki—RDoc’s new default theme.
A Fresh Look for Ruby Documentation
Ruby has always been a joy to write, and now reading Ruby documentation can match that experience. Aliki brings a modern, clean design to docs.ruby-lang.org and any gem that generates documentation with RDoc v7.0+.
Key Features
- Improved search: Case-aware ranking, fuzzy matching, and support for searching constants
- Dark mode: Respects your OS preference with a manual toggle
- Three-column layout: Left sidebar for navigation, center for content, right sidebar for table of…
- Code block…
Passenger 6.1.1

Version 6.1.1 of the Passenger application server has been released. This release adds packages for Ubuntu 25.10 "questing", and removes packages for Ubuntu 25.04 "plucky". Compatibility with the upcoming Ruby 4 is also improved.
Passenger 6 introduced Generic Language Support, or: the ability to support any and all arbitrary apps.
Nginx Uploads Bug
Passenger 6.1.1 includes a fix for a bug where if Passenger was loaded via the Nginx module, and had passenger_request_buffering off; then any request body larger than the client_body_buffer_size would be corrupted.
Future Ruby Versions
Passenger 6.1.1 has improved support for Ruby 4 and Frozen String Literals.
Updates & improvements
- [Ubuntu] Add…
Ruby has always been a joy to write. But for a long time, reading Ruby documentation on docs.ruby-lang.org hasn’t really matched that experience.
Last year, I brought a new look to the Darkfish theme by updating its visuals and improving mobile support. It was a visible improvement, but it wasn’t enough.
So this year, I built something new from the ground up. Starting with RDoc 7.0.0, Aliki is now the default theme for RDoc.
This release also coincides with Ruby’s 30th anniversary and the redesign of ruby-lang.org—a great moment to give Ruby’s documentation a fresh look as we head into the next chapter with Ruby 4.0.

Why a New Theme?
Even after last year’s improvements, I still…
Each morning I open four tabs: Calendar, Gmail, Jira, and Obsidian. I read all, discard low priority emails or calendar events, and start building a mental picture of what I’ll do that day, and when exactly. For each piece of data I decide whether it’s time sensitive or not, whether I need to prepare beforehand, and whether I should tackle it later (or never). After warming up my brain, I kick off the actual work.
I decided an LLM should do that pre-work instead of my well-rested brain. To build such automation I’d practice Claude Code subagents and local MCP servers setup,
a good exercise for my new startup, RailsPilot.ai. So I started creating my /today Claude Code command.
/today…
Rewrite with Confidence: Validating Business Rules Through Isolated Testing
Rewrite with Confidence: Validating Business Rules Through Isolated Testing
A few months back, our team at Arkency faced a challenge that many Rails developers might recognize. We needed to implement a new flow at Lemonade that would eventually replace a legacy process — but with three major constraints that couldn’t be compromised: user experience, cost efficiency, and avoiding technical debt.
The stakes were high. Any discrepancies between systems would impact customers and potentially create legal issues in the insurance domain. We had just three months to understand, replicate, and improve a complex flow that had evolved organically over years. And we needed to break free from…
486: ActiveModel Everywhere
Aji and Sally join forces to discuss the different ways they utilise active models in their workflows.
Aji describes a new system for working with active models they’ve been using recently, Sally recalls a project where active models could have saved her a lot of time, before putting their heads together to think of new creative ways to utilise rails’ tools toolset to build other active models.
—
Discover more of The Magic of Rails through Eileen Uchitelle’s Keynote, or check out the GitHub repo mentioned in this episode.
Thanks to our sponsors for this episode Judoscale - Autoscale the Right Way (check the link for your free gift!), and Scout Monitoring.
Your hosts for this…
4.0.3 Released
RubyGems 4.0.3 includes enhancements and documentation and Bundler 4.0.3 includes enhancements.
To update to the latest RubyGems you can run:
gem update --system [--pre]
To update to the latest Bundler you can run:
gem install bundler [--pre]
bundle update --bundler=4.0.3
RubyGems Release Notes
Enhancements:
- Installs bundler 4.0.3 as a default gem.
Documentation:
- Fix broken documentation links. Pull request #9208 by eileencodes
Bundler Release Notes
Enhancements:
- Fall back to ruby platform gem when precompiled variant is incompatible #9211
Manual Installation
To install RubyGems by hand see the Download RubyGems page.
SHA256 Checksums:
- rubygems-4.0.3.tgz
f5f…
✉️ Merry Divestmas
This is a copy of the Searls of Wisdom newsletter delivered to subscribers on December 20, 2025.
Hey everybody, we've almost survived another year! Just ten days to go—I hope we all make it!
Looking back on the home stretch of 2025, this is all I have to report since our last issue:
- I built a sexy new gaming PC over 3 days, 120 teeny-tiny M3 screws, and at least ten cups of coffee
- I got my first nose job. I've always had a huge fucking nose, and I'm relieved to finally be able to breathe out of it
- I talked about both of the above on my podcast
- I'm so sick of bracing for the AI bubble to pop, that I've decided to look forward to it instead. Buy popcorn futures, everyone 🍿
- I released…
T…
Happy Holidays

Happy holidays everyone! Have a great rest of the year!

While going through recently merged PRs in Rails, I came across a new feature from DHH, that handles a common concern in app configuration: managing credentials across different configuration backends in a single, consistent manner.
When you're going through the PR, I highly recommend you also read Jean's (byroot) code review comments and how DHH addresses them…

