Hello! 8 years ago, I wrote excitedly about discovering Tailwind.
At that time I really had no idea how to structure my CSS code and given the
choice between a pile of complete chaos and Tailwind, I was really happy to choose
Tailwind. It helped me make a lot of tiny sites!
I spent the last week or so migrating a couple of sites away from Tailwind and
towards more semantic HTML + vanilla CSS, and it was SO fun and SO interesting,
so here are some things I learned!
As usual I’m not a full-time frontend developer and so all of my CSS learning
has happened in fits and starts over many years.
it turns out Tailwind taught me a lot
When I started thinking about structuring CSS, I was intimidated…
I attended Blue Ridge Ruby for the first time and had a great time speaking and participating in the conference held in Asheville, North Carolina. The following are a learnings and experiences that might be of interest.
Conference
Both my wife and I traveled together so she could work on her novel and I could focus on the conference then have time to…
Stripe Changes, File Upload Quirks, Scaling Sidekiq
Chris and Andrew catch up after Andrew’s whirlwind “vacation-ish” road trip before diving into Stripe’s latest announcements, usage-based billing, merchant-of-record pricing, Rails file upload quirks, Active Storage image handling, Sidekiq queue strategy, and the future of RubyGems. They also discuss browser form behavior, preserving and deleting attachments, image variant performance, and how to think more clearly about background job priorities. Hit download now to hear more!
Links
May 14, 2026 In-depth technical analysis · RubyStackNews · Concurrency & Performance For decades, the Global VM Lock (GVL) — also known as the GIL — was CRuby's great concession: the safety and simplicity of an object model free of data races, in exchange for not being able to execute Ruby code in parallel within … Continue reading Ractors: Real Parallelism in Ruby Without the GVL →
Added an MCP server and CLI commands to use Rails Blocks easily.
View full changelog →
I’ve been working professionaly with Ruby on Rails for nearly 15 years (I’m also the author of GoodJob and Spectator Sport). Last year I left GitHub and co-founded a technology startup, Frontdoor Benefits, that helps people enroll and manage their US government welfare benefits like SNAP/EBT.
Therefore, I’ve been working in a fresh Ruby on Rails app full-time now for 1 year. One of the Rails pillars is “convention over configuration”, so I thought it would be fun to share what has so far accumulated in my app’s /config directory: monkeypatches, extensions, and appwide behaviors.
Let’s start with the most controversial one.
Object#not_nil? and boolean extensions
The preview route derives an example name from the URL and calls it
with `public_send`. The code does not verify that the requested
method is one of the preview examples explicitly defined by the
preview class.
As a result, inherited public methods on `ViewComponent::Preview`
are route-reachable. The most important one is `render_with_template`,
which accepts `template:` and `locals:`. Those values can come from
request params and are later passed to Rails as `render template:`.
If previews are exposed, an attacker can render internal Rails
templates that are not otherwise routable.
Severity: High if preview routes are externally reachable; Medium otherwise.
The system test entrypoint canonicalizes a user-controlled file path
with `File.realpath`, then checks whether the resolved path starts
with the temp directory path. This is not a safe containment check
because sibling directories can share the same string prefix.
Severity: Medium; test-route scoped.
Custom elements have been covered here berfore. If you have used Hotwire in Rails, you have already used them. Both <turbo-frame> and <turbo-stream> are custom elements. They are just HTML tags with JavaScript behavior attached.
This article walks through building a drag-and-drop image upload custom element that works great in Rails forms. Starting with a simple avatar and ending with a reusable component that handles both inline and external forms. The code is, as usual, available on GitHub.
So first, why not use a regular file input or a Stimulus controller? The answer is that custom elements are perfect for self-contained components. They work anywhere in your HTML without needing to…
Redesign prep matters, but what does it actually look like when AI is in the room?
Continue Reading
I paid five dollars to read a Medium article about my own free, open source library. It was sold as hard-won production experience.
It was fabricated.
The first code sample used RubyLLM.client, which does not exist. It called client.chat(messages: ...), which does not exist. Then it invented RubyLLM::StreamInterrupted, RubyLLM::APIError, and a stream: proc API that RubyLLM has never had.
The problem was not merely wrong information. Wrong information can be corrected. This was sold as experience with RubyLLM in production, which is a much more valuable claim.
AI slop is not just filling the web with predictable cadence. It is fabricating experience. It is letting people skip the work,…
May 12, 2026 If you still think Ruby’s Array is “just a C struct with some methods on top,” you’re about 5 years out of date. Modern MRI tells a very different story. Today, Array sits at the intersection of: Ruby code (array.rb) VM intrinsics (Primitive.*) C runtime (array.c) JIT specialization (YJIT) And the result … Continue reading MRI Internals: How Ruby Arrays Became a VM Playground →
Why should you choose Solidus versus Spree? The projects share a common history up until 2015. That year, Solidus forked off of Spree and began a new direction. Since then, a lot has changed, but a lot has stayed the same.
Before we dive into the differences, it’s important to understand the history. Solidus is a community-led fork of Spree that kicked off shortly before the corporate backing of Spree evaporated, leaving the project unmaintained. The project ultimately picked up new leadership, but during that gap much of the community moved to the new fork. You can see the gap in Spree’s commit frequency:
If we look at Solidus’s commit frequency, you instead see a…
Have you ever worked on a brand new codebase with talented engineers, only to find out a year later that it turned into the same “archaeological strata of quick fixes” as your last legacy project? I know I have, and it happened many times.
My go-to blame target for this was usually micromanagement and imposed unrealistic deadlines. And I’m sure these play a significant role in it. But a recent conversation led me to understand another cause of this – untimely feedback. Or, to be precise, feedback that was requested or given too late.
I think many of us know the story. Someone starts working on a new capability. They spin off a feature branch and keep tinkering with it for a couple of…
Last week, I spent an extended weekend in Rimini, Italy, for the first edition of Rubycon where I gave a lightning talk connecting my reconversion story with the current trend of throwing junior developers under the bus for the sake of (AI) productivity.
One engine, many tools
A few years ago, the new Ruby parser Prism was released. One of its primary goals was to unify the community since we
had multiple implementations of Ruby parsers, each with their own bugs, differences in implementation and portability.
By having a single parser, community investments in performance and correctness benefit every single tool built on top
of it (including Ruby itself!).
However, the story of repeated implementations of highly complex foundational blocks doesn’t end at the parser level.
Move one level up the stack and the pattern repeats. Today, we have multiple tools that implement code indexing and
related static analysis algorithms. Consider just…
Ruby 4.0.4 has been released.
This is a routine update that includes bugfixes.
Please see the GitHub Releases for further details.
Release Schedule
We intend to release the latest stable Ruby version (currently Ruby 4.0) every two months following the most recent regular release. Ruby 4.0.5 will be released in July, 4.0.6 in September, and 4.0.7 in November.
If a change arises that significantly affects users, a release may occur earlier than planned, and the subsequent schedule may shift accordingly.
Download
We’re excited to share that Gusto has become the first company to join the Ruby Alliance.
The Ruby Alliance is a small coalition of companies that are choosing to make a significant investment in the long-term health, resilience, and sustainability of the Ruby ecosystem and the infrastructure it depends on.
We are honored and humbled by how quickly and decisively Gusto moved to join us. They didn’t wait to see what other companies would step forward. They recognized the importance of this moment and chose to lead the way.
Ruby has always thrived because individuals and companies invested back into the ecosystem that supports their teams and businesses every day. Gusto’s leadership is a…
When you’re building views in Rails, you often need to apply CSS classes conditionally. Maybe a nav link should look different when it’s the current page, or a form field needs error styling. Since Rails 6.1, the class_names helper does this cleanly.
Instead of…
…interpolating conditional classes with ternaries or post-statement conditionals:
<div class="p-4 rounded <%= @error ? 'bg-red-50 border-red-500' : '' %> <%= 'opacity-50 cursor-not-allowed' if @disabled %>">
<%= @message %>
</div>
Use…
…the class_names helper:
<%= tag.div class: class_names(
"p-4 rounded",
"bg-red-50 border-red-500": @error,
"opacity-50 cursor-not-allowed": @disabled
) do %>
<%= @message %>
<% end %>…
String arguments are always applied; trailing keyword-style entries are included when their value is truthy and silently dropped otherwise.
…
## Summary
Nokogiri's CSS selector tokenizer contains regular expressions whose construction may result in exponential regex backtracking on adversarial selectors. Three ReDoS vectors are addressed in this release:
1. String-literal tokenization on certain unterminated quoted-string input.
2. String-literal tokenization on a separate class of hex-escape-rich input.
3. Identifier tokenization on hex-escape-rich input.
The public CSS selector methods that funnel through the affected tokenizer are `Nokogiri::CSS.xpath_for`, `Node#css`, `Node#at_css`, `Searchable#search`, and `CSS::Parser#parse`.
## Mitigation
Upgrade to Nokogiri `>= 1.19.3`.
If users are unable to upgrade, two options…
## Summary
Nokogiri's `Nokogiri::XSLT::Stylesheet#transform` leaks a small heap allocation when passed a Ruby string parameter containing a null byte.
For applications that pass attacker-controlled input through `XSLT.transform` parameters, this may be a vector for a denial of service attack against long-running processes.
## Mitigation
Upgrade to Nokogiri `>= 1.19.3`.
Users may also be able to mitigate this issue without upgrading by validating untrusted transform parameters before passing them to `Nokogiri::XSLT::Stylesheet#transform`.
## Severity
The Nokogiri maintainers have evaluated this as **Moderate Severity**, CVSS 5.3.
Each leaked allocation is approximately 24–32 bytes,…
Introducing ruby-charts: Native Charts for Ruby May 10, 2026 Last Friday I released ruby-charts, a gem for generating charts directly in Ruby—no JavaScript, no external APIs. Built for Ruby on Rails Build Maps WithoutGoogle APIs Generate beautiful production-ready maps directly from your Rails backend. Fast rendering, zero external dependencies, full control. View Live Demo → … Continue reading
Introducing ruby-charts: Native Charts for Ruby →
Rails 8 ships Thruster in the default Docker flow.
Use it for simple, single-container apps.
Keep Nginx when we need edge features.
Puma stays as the app server.
Thruster runs in front of Puma
and handles the common reverse-proxy duties.
What is Thruster?
Thruster
is a lightweight, Go-based HTTP/2 proxy
from 37signals.
It runs alongside Puma and provides:
- HTTP/2 support
- Optional automatic TLS certificates with Let’s Encrypt
- Basic HTTP caching for public assets
- X-Sendfile support for efficient file serving
- Gzip compression
Before
Before Rails 8,
a simple production setup often looked like this:
- Puma as the application server
- Nginx or Apache as a reverse proxy
- Certbo…
Show users live progress on long-running background jobs using Rails 8.1's structured event reporter and Active Job Continuations, with no polling and no per-job broadcast wiring.
At FastRuby.io, we spend a lot of time upgrading Ruby and Rails applications. However, we do more than just that,
we also pay attention to other areas of the application that can be improved. For example, we recently migrated a
customer’s application from Sprockets to JS bundling with esbuild.
In this article, I share my experience migrating from Sprockets to
JS Bundling (JavaScript Bundling for Rails).
This is not a step-by-step guide, as each application has its own unique needs. Instead, I discuss the problems
I encountered and the approach I took during the migration to JavaScript bundling.
Why We Needed to Migrate
Before we discuss why we needed to migrate, let me give you some…
Direct Routes and Data Queries
On this episode of Remote Ruby, Chris, Andrew, and David kick things off with dentist trauma, gold star stickers, and fiber internet. The conversation centers on Rails direct routes, why they can be more powerful than helpers, the upcoming Rails World CFP and ticket rush, how AI is becoming more practical inside real engineering teams, a reminder to fill out the Rails survey, and Chris’s continued work expanding the Rails Getting Started Guide into a more realistic e-commerce tutorial with wishlists, reviews, ratings, and product images. Hit download now to hear more!
Links
Hi, it’s zzak. This week was full of changes, so grab a seat, there’s a lot to cover.
New Accessibility Guide open for review
The Rails Foundation is working on a new Rails-flavored Accessibility Guide, covering semantic HTML, ARIA, page structure, forms, Turbo interactions, CSS, and testing. Please take a look and share feedback on the pull request.
Add ActiveJob::Attributes to persist data between steps
Active Job can now declare typed attributes that are serialized with the job and restored on resume, removing the need to override serialize and deserialize.
class SubmitEnrollmentJob < ApplicationJob
include ActiveJob::Continuable
attribute :payment_token, :string
end
Add…
May 7, 2026 Modern chart rendering usually assumes a browser, a JavaScript runtime, or a frontend stack. But many Ruby applications do not actually need interactive dashboards. They need deterministic image generation. Things like: scheduled reports PDF exports transactional emails admin dashboards analytics snapshots CI metrics server-side rendering pipelines That was the motivation behind building … Continue reading Generating Charts in Pure Ruby Without JavaScript →
Uma história real de upgrade para Rails 8: como evoluir uma aplicação existente, preservar seu valor e seguir em frente sem começar do zero.
Continue Reading
Over the last decade, a great deal of data privacy regulations have been passed in the European Union. Like it or not, measures like GDPR, the Digital Services Act, and the upcoming Artificial Intelligence Act are exerting increasing influence across industries over how and especially where the data of European customers is stored.
In this article, we will explore the ways to keep the simplicity of a Platform as a Service (PaaS) while utilizing only European providers.
Why Data Sovereignty Matters More Than Ever
The General Data Protection Regulation (GDPR), which was ratified in 2016, granted fundamental rights to the "data subject". These include the right of access, the right of…
#799 — May 7, 2026
Read on the Web
Ruby Weekly
Ruby Concurrency: What Actually Happens — A from-the-ground-up tour of processes, Ractors, threads, and fibers. Concurrency is a common source of confusion, but this guide helps clear up when to reach for which primitive, complete with benchmarks, sequence diagrams, and traces of what happens behind the scenes.
Carmine Paolino
AI Uncertainty and Pressure Causing Existential Dread? — It’s real, and you’re not alone. C-suites pushing AI mandates without strategy. Teams with varying levels of fluency. AI workflows aren’t productive. Test Double offers confidential pairing…
In a previous article, I explored building nested forms with Stimulus. But what about when you need to edit existing questions, remove ones you no longer need or reorganize them? Let’s extend that foundation by adding: editing, deleting and repositioning questions using drag-and-drop.
This article builds directly on the previous setup, so make sure you have that in place before continuing (check out the repo for the full code base). The reposition logic is inspired by this article to create a Kanban board.
First, update the migration to include a unique index:
class AddPositionToQuestions < ActiveRecord::Migration[8.1]
def change
add_column :questions, :position, :integer, null: false
…
I like the positioning gem for this, make sure to set it…
A shorter companion piece to the latest RailsRevelry article on the hidden dispatch layer between route matching and controller action execution.
I released RubyLLM 1.15 today.
It ships image editing, cost tracking, cleaner token accounting, inferred tool parameters, additive callbacks, and Rails fixes.
The theme is simple: stop making me write glue code. If the computer can infer it, RubyLLM should infer it. If a provider reports usage, RubyLLM should turn it into cost. If Rails already has a blob, RubyLLM should not download it and upload it again.
Image Editing
RubyLLM.paint could already generate images:
image = RubyLLM.paint("A watercolor robot holding a Ruby gem")
Now with: turns it into an image edit:
image = RubyLLM.paint(
"Turn the logo green and keep the background transparent",
model: "gpt-image-1",
with:…
My good mate Yaroslav wrote about his new solution for bundling a complete Bun runtime inside a gem - by all means, give it a read.
A lot of points he makes are very sensible, but for a few months now I have decided that - for myself - I will not be using any frontend bundling nor JS runtime at all. Here’s how you can do the same.
How useful is an asset pipeline?
There is, in fact, just one sensible use case for needing an asset pipeline, and it goes as follows.
- You are running revision
abc0 on two machines, box1 and box2
- You make some glorious changes to your frontend code, and a new version gets prepared which requires those changes to be applied to the frontend assets your users…
For quite a few years the Rails project has been working with the Internet Bug Bounty (IBB).
The IBB is an organization that awarded cash to security researchers that reported issues to OSS projects participating in the IBB.
For quite a while I wasn’t certain about my feelings toward the program because I felt like cash rewards could incentivize low quality reports as well as encourage reporters to “haggle” about the severity of a particular bug (the IBB paid more when the bug was more severe).
In the beginning that certainly was the case.
We were fielding many low quality reports, and people were haggling over severity.
But the program evolved, and despite the never-ending haggling, I felt…
Authors: Pavel Grinchenko, Frontend Engineer, and Travis Turner, Tech Editor
Topics: Performance, Open Source, JavaScript, TypeScript, Astro.js, React

Most marketing sites ship a SPA framework just to toggle a sidebar. Here's how we migrated an Astro site from React and Ark UI to native Web Components: 100 KB less JavaScript, no functionality lost, and a tiny library called nanotags that makes Custom Elements enjoyable to write.
A while ago, I shipped a marketing site built with Astro, React, and Ark UI. It worked fine, the deadline was tight, and React was the right call at the time. But I always knew I'd come back to it. Months later, I did. The result: 100 KB less JavaScript and no…
Introduction
I just returned from RubyKaigi 2026, held from April 22nd to 24th in Hakodate, Hokkaido. For those unfamiliar with it, RubyKaigi is the biggest Ruby conference in the world, drawing speakers, committers, and Rubyists from across the globe. As always, it managed to combine deep technical talks with a uniquely Japanese atmosphere that no other conference comes close to.
This year's edition had a distinctly Hokkaido feel: the cold winds of the northernmost island, the smell of the sea, kaiseki dinners, sashimi at conference parties, and onsens - a lot of onsens. The conference itself was in the south of Hokkaido (Hakodate). Still, for me, the trip extended significantly further…
Do you need to build a State Machine at least once in your career? May 5, 2026 Probably not. Built for Ruby on Rails Build Maps WithoutGoogle APIs Generate beautiful production-ready maps directly from your Rails backend. Fast rendering, zero external dependencies, full control. View Live Demo → Read Docs ✓ No API fees ✓ … Continue reading Do you need to build a State Machine at least once in your career? →
Frequently Played 🔗
I tend to listen to the same songs or albums on repeat that are evocative of how I’m feeling or what’s going on with me. Here is what I’m currently listening to over, and over, and over, and over, again.
As Alive As You Need Me To Be 🔗
Dive into the album. The NIN x Boys Noize collaboration builds on their work together on the B stage during the Peel It Back tour.
Full Lyrics
I never had a choice, connection
I never had a chance to catch my breath
One Of The Greats 🔗
The dirty riff, pointed lyrics, and stilted delivery are a fantastic combination.
Full Lyrics
Did I get it right? Do I win the prize?
Do you regret bringing me back to life?
…
I will let the light in, I will let some…
Blue Ridge Ruby 2026 🔗
I returned to Asheville for the first time since 2023. Both times for the Blue Ridge Ruby conference. Both times convinced for the same reason: organizer Jeremy Smith. Both times because I was selected as a speaker.
This post is not intended as a review of any of the talks, but to highlight the variety of great work from all involved. I hope you’ll seek out the full videos of all the sessions that interest you once they are available.
Preparing 🔗
Jeremy Smith conducted interviews with many of the speakers prior to the conference. Jeremy and I chatted about various topics related to conferences and writing. Beyond that, I mostly followed my own advice.
Day 1 🔗
Learning from…
AI-first Engineering is now the operating default in many organizations, including mine. Developers have kept up. Vibe coding became agentic engineering, and the race towards truly autonomous engineering isn’t slowing.
But what are we, managers, to do?
A manager job continues to include recruiting and retaining people, setting clear goals and expectations, fostering communication, owning team workflows, and coaching daily behaviors. To this list we must now add driving AI transformation.
Being a passive advocate is not enough. Unlike other subjects, no amount of AI training will help you keep up with the pace of evolution of this technology. Therefore, one cannot drive AI transformation…
Authors: Gleb Stroganov, Product Designer, Varya Nekhina, Account Manager, and Travis Turner, Tech Editor
Topics: Case Study, Developer Products, Product development, Developer marketing, Google Analytics

A story of validating product demand on a $2K budget with 128 cold-traffic signups, an A/B winner at 95% confidence, and a sequenced playbook founders can run themselves.
Building a product is one thing; knowing someone is willing to pay for it is another. After shipping Thicket's marketplace in 2 weeks, Evil Martians built a full demand validation infrastructure around it. The results were 36K impressions, 128 cold-traffic waitlist joins, a landing page variant confirmed at 95% statistical…
I released kamal-backup today.
I run Chat with Work on Kamal, and I needed backups. There are already Kamal accessories for database backups. None of them also back up Active Storage. None use restic, so encryption, deduplication, and repository checks are on you. None ship a CLI with restores and drills. None produce evidence you can hand a security reviewer.
So I built one.
A gem and a Docker image
kamal-backup is two pieces: a Ruby gem you add to your Rails app, and a Docker image you boot as a Kamal accessory. They point at a restic repository you bring yourself.
The gem is your CLI. Local commands run directly on your machine using restic. Production-side commands shell out…
Introduction
Ship small nonroot images,
scan for CVEs,
and let Kamal gate traffic.
Rails 8.1 gives us that path by default.
- Pin Ruby and keep it synced with
.ruby-version
- Use multistage builds
- Precompile gems, app code, and assets during build
- Run production containers as a nonroot user
- Fail CI on high and critical CVEs
While our previous guide covered
Rails 8 adds Kamal by default,
this post focuses on containerization best practices,
security hardening,
and production optimization techniques.
The examples below use Rails 8.1,
Ruby 3.4.9,
and Kamal 2.11.0.
Understanding Rails Docker Setup
When we create a new Rails 8.1 application,
it generates several Docker related…
A while back I decided to stop using Tailwind for new projects and to just write
vanilla CSS instead.
But one thing I missed about Tailwind was the colour palette (here as CSS).
If I wanted a light blue I could just use blue-100 and if I didn’t like it
maybe try blue-200 or blue-50. I’m not very good with colours so it makes
a big difference to me to have a reasonable colour palette that somebody who is
better at colour than me has thought about.
But I’m also a little tired of those Tailwind colours, so I asked on Mastodon
today what other colour palettes were out there. And then a friend said they
wanted links to those colour palettes, so here’s a blog post so my friend can
see them, and…
What changes when Rails work leaves the request-response path and starts running later, elsewhere, or under a different failure model.
When you need to build HTML outside of a template, it’s tempting to concatenate strings and call html_safe on the result. This bypasses Rails’s built-in XSS protection entirely: any user input in that string goes straight to the browser unescaped.
The good news is you almost never need html_safe. Rails provides three underappreciated tools that handle escaping for you.
Instead of…
…calling html_safe on strings you’ve built by hand:
def status_badge(label, color)
"<span class=\"badge badge-#{color}\">#{label}</span>".html_safe
end
def formatted_address(user)
[user.street, user.city, user.postcode].compact.join("<br>").html_safe
end
def render_comment(comment)
comment.body_html.…
Use…
…the right tool for…
Oh Asheville! How wonderful, weird, and full of art you are! Aside from returning with sore shins (central Ohio isn’t known for its hills…), Adam and I head home from North Carolina with two primary reflections we feel worth sharing here.
Ye old Blue Ridge Mountains
1. “Humans are the X-factor”. There’s something irreplaceable about a gathering of humans in-person; something unmistakably creative and promising. Something you feel more than you can describe; a moment where the whole is indeed greater than its constituent components. Small Ruby conferences ooze this feeling! My point here is simply that there is no replacement for…
### Summary
`Net::IMAP::ResponseReader` has quadratic time complexity when reading large
responses containing many string literals. A hostile server can send
responses which are crafted to exhaust the client's CPU for a denial of
service attack.
### Details
For each literal in a response, `ResponseReader` rescans the entire growing
response buffer. The regular expression that is used to scan the response
buffer runs in linear time. With many literals, this becomes O(n²) total
work. The regular expression should run in constant time: it is anchored to
the end and only the last 23 bytes of the buffer are relevant.
Because the algorithmic complexity is super-linear, this bypasses…
### Summary
A man-in-the-middle attacker can cause `Net::IMAP#starttls` to return
"successfully", without starting TLS.
### Details
When using `Net::IMAP#starttls` to upgrade a plaintext connection to use TLS,
a man-in-the-middle attacker can inject a tagged `OK` response with an easily
predictable tag. By sending the response before the client finishes sending
the command, the command completes "successfully" before the response handler
is registered. This allows `#starttls` to return without error, but the
response handler is never invoked, the TLS connection is never established,
and the socket remains unencrypted.
This allows man-in-the-middle attackers to perform a STARTTLS…
### Summary
When authenticating a connection with `SCRAM-SHA1` or `SCRAM-SHA256`, a
hostile server can perform a computational denial-of-service attack on the
client process by sending a big iteration count value.
### Details
A hostile IMAP server can send an arbitrarily large PBKDF2 iteration count in
the SCRAM server-first-message, causing the client to perform an expensive
`OpenSSL::KDF.pbkdf2_hmac` call. Because the PBKDF2 function is a blocking C
extension and holds onto Ruby’s Global VM Lock, it can freeze the entire Ruby
VM for the duration of the computation.
OpenSSL enforces an effective maximum by using a 32-bit signed integer for the
iteration count, Depending on hardware…
### Summary
Several `Net::IMAP` commands accept a raw string argument that is sent to the
server without validation or escaping. If this string is derived from
user-controlled input, it may contain contain `CRLF` sequences, which an
attacker can use to inject arbitrary IMAP commands.
### Details
`Net::IMAP`'s generic argument handling, used by most command arguments,
interprets string arguments as an IMAP `astring`. Depending on the string
contents and the connection's UTF-8 support, this encodes strings as either a
`atom`, `quoted`, or `literal`. These are safe from command or argument
injection.
But the following commands transform specific String arguments to
`Net::IMAP::RawData`,…
### Summary
Symbol arguments to commands are vulnerable to a CRLF Injection / IMAP Command
injection via Symbol arguments passed to IMAP commands.
### Details
Symbol arguments represent IMAP "system flags", which are formatted as "atoms"
(with no quoting) with a `"\"` prefix. Vulnerable versions of Net::IMAP sends
the symbol name directly to the socket, with no validation.
Because the Symbol input is unvalidated, it could contain invalid `flag`
characters, including `SP` and `CRLF`, which could be used to finish the
current command and inject new commands.
Although IMAP `flag` arguments are only valid input for a few IMAP commands,
most Net::IMAP commands use generic argument…
In this episode, we look at where we were years ago and the journey where we have landed today. Over the past 10 years, much has changed with our approach to client interactions and in the episode we explore my favorite and current approach.
Building client-side routing with vanilla JavaScript: What started as a simple experiment revealed the hidden complexity that SPA frameworks solve for you.
Hello! One of my long term projects on here is
figuring out how to write frontend Javascript without using Node
or any other server JS runtime.
One issue I run into a lot in my frontend JS projects is that I don’t know how
to write tests for them. I’ve tried to use Playwright in the past, but it felt
slow and unwieldy to be starting these new browser processes all the time, and
it involved some Node code to orchestrate the tests.
The result is that I just don’t test my frontend code which doesn’t feel great.
Usually I don’t update my projects much either so it doesn’t come up that much,
but it would be nice to be able to make changes with more confidence!
So a way to do frontend testing…
Build per-plan API rate limits (free, pro, enterprise) using Rails 8.2's dynamic rate_limit options, with no Rack::Attack or custom middleware.
Behind the Scenes: Developing Podias New Version
Chris, Andrew, and David open with some classic confusion over what day it is then dive into Podia’s gradual rollout of a major new app version, including how the team is handling migration, feature flags, dogfooding, and eventual cleanup. From there, the discussion turns to underrated Rails routing features like direct routes and resolve routes, a newly merged Rails query command, observability improvements through Hatchbox’s AppSignal integration, and the ongoing pain of CSS build tooling in Rails apps. They also touch on conference season and their upcoming talks. Press download now to hear more!
Links
Classes are at the heart of Object-Oriented Programming and Ruby makes them effortless to use. They provide the following benefits:
-
Composition: Allow you to leverage the Dependency Inversion Principle (DIP) — the "D" in SOLID design — by injecting dependencies via your constructor or methods. Prefer composition over inheritance because this maximizes your ability to reuse your components to build robust architectures.
-
Inheritance: Allow you to subclass and inherit behavior from a superclass and/or use multiple inheritance to enhance your class with common functionality.
-
Encapsulation: Allows you to wrap data, state, and/or behavior (methods) within a single…
Hi, it’s Greg, bringing you the latest updates about Rails.
Updated guides await community input
The Asset Pipeline, Layouts & Rendering, Caching, and Active Job Basics Guides
have all recently been updated and are open for community input. If you have
time and would like to help review, please check the list of pull requests.
Apply for the Rails at Scale Summit
Reminder to apply by May 8 for the Rails at Scale Summit (Sept 22, Austin), a
one day, invite-only gathering for engineers working on large-scale Rails
applications.
Enable frozen string literal by default
New Rails apps now include a config/bootsnap.rb file that enables frozen string
literals. This only impacts the application…
It is also possible to enable…
If you’ve followed Hanami for a while, you’ll know we’re rather fond of flowers. Today our garden has grown: Hanami, Dry, and Rom — three projects that have lived alongside each other across a decade and billions of downloads — are finally coming together as one. Welcome to Hanakai!
With Hanakai, we’re building a single shared community around the gems you know and love. The gems will carry on, now cared for by a bigger, unified team. And with our beautiful new website, now you can discover our vision for Ruby more easily than ever.
Loosely translated from the Japanese 花会, Hanakai means “flower fellowship”, sharing its first character 花 with Hanami, “flower viewing”. With…
Two weeks ago, the NPM endpoint that yarn audit from Yarn v1 uses, decided to stop working:
I imagine this won't be fixed (unfortunately), but it looks like npm has silently deprecated the security audit API that Yarn 1 uses:
yarn audit v1.22.22
error Error: https://registry.yarnpkg.com/-/npm/v1/security/audits: Request "https://registry.yarnpkg.com/-/npm/v1/security/audits" returned a 410
at params.callback [as _callback] (/usr/share/yarn/lib/cli.js:66689:18)
at self.callback (/usr/share/yarn/lib/cli.js:141410:22)
at Request.emit (node:events:517:28)
at Request.<anonymous> (/usr/share/yarn/lib/cli.js:142382:10)
at Request.emit (node:events:517:28)
at…
For years, our way of taking over legacy systems was simple: start small.
A client would come to us with an existing application and a list of things they needed done. Sometimes that list was mostly bugs. Sometimes it was features. Sometimes it was a mix of vague product wishes, or urgent production issues.
So we would begin with the safest tickets.
Fix a small bug. Change a minor behavior. Add a low-risk feature. Read the code around it. Ask questions. Ship. Repeat.
Starting with low-risk work lets us deliver value to the client while we build confidence and learn the codebase we’re working on.
As the weeks went by, we would move toward more complex parts of the system. By then, we…
Software consultancy and Rails Foundation member Planet Argon is once again collecting real-world insights from Rails developers and turning them into something the whole community can learn from.
The survey takes a deep look at how Rails is actually used today, including the tools people rely on, how teams and workflows are set up, how apps are built and deployed, and the challenges developers face. It also explores how AI is finding its place in everyday Rails work.
All results are shared openly, giving the community a clear, data-driven view of where things stand.
At RubyMine, we’re genuinely glad to see work like this continue. It takes real effort to run a survey at this…
#798 — April 30, 2026
Read on the Web
Ruby Weekly
Spinel: An Ahead-of-Time 'Ruby' Compiler from Matz — Armed with AI, Matz has built a self-hosting compiler (for a subset of Ruby) that emits C which is then compiled to a native binary. It uses Prism for parsing and performs type inference. There are severe limitations (no eval or metaprogramming) and it can’t replace CRuby, but the performance potential is significant, though it's not a truly like-for-like comparison.
Yukihiro 'Matz' Matsumoto
💡 I'm working on a deeper dive of Spinel for next week. There's a lot of interesting stuff to chew on, even as a…
The meetup took place last Friday, April 24th, at the FaHCE (Facultad de Humanidades y Ciencias de la Educación) in La Plata. The talks came from different places: empirical software engineering, custom coding agents, and multi-agent systems. The conversations continued afterward over beers and food provided by the organization.
Empirical software engineering: the scientific compass in the age of LLMs
The first talk was “Ingeniería de software empírica: La brújula científica en la era de los LLMs” (“Empirical software engineering: the scientific compass in the age of LLMs”) by Florencia Riva, a sociologist working at LIFIA.
Florencia’s talk pushed against a common temptation: asking LLMs…
Nine months ago, I introduced Perron, an OSS Rails-based static site generator. 190 commits and 18 releases later, lots of bugfixes and many new features—by yours truly and a few others—have been added. Today I am thrilled to announce Perron 1.0. 🥳
Want to check it out right away? Check out the docs, star it on GitHub or explore the showcase to see what others have built. 😻
Programmatic SEO
One of the most exciting features has been the ability to generate content programmatically. Whether you are building a SaaS directory, product comparison pages or anything else that mixes data with thousands of pages, with Perron this is now super easy.
Learn more about programmatic content creation.
…
RubyGems 4.0.11 includes enhancements and Bundler 4.0.11 includes enhancements, bug fixes and documentation.
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.11
RubyGems Release Notes
Enhancements:
- Add commented-out rubygems_mfa_required to bundle gem template. Pull request #9487 by MatheusRich
- Clarify the name and meaning of the first argument to
gem spec. Pull request #9476 by eregon
- Installs bundler 4.0.11 as a default gem.
Bundler Release Notes
Enhancements:
- Update gem creation guide URL to rubygems.org. Pull request #9500 by nissyi-gh
- Lo…
On April 23rd, we submitted a vulnerability report to the Nokogiri maintainers. It was the first one our team has filed using AI-assisted scanning. The maintainers accepted the report and published it as GHSA-c4rq-3m3g-8wgx.
The same week, news broke that Mythos, Anthropic’s most capable security model, had been accessed by unauthorized users through a third-party vendor. According to Anthropic, Mythos has identified thousands of zero-day vulnerabilities across every major operating system and web browser, including a 17-year-old remote code execution flaw in FreeBSD and a 27-year-old bug in OpenBSD. Two stories on the same shift, one from each side of it. The capability gap between…
…
Like a lot of developers right now, I’m figuring out how to support a “supervising several parallel development efforts at once” workflow. If you look for information on the web about how to implement a workflow like this, you’ll see a lot about git worktrees—where a single .git directory serves multiple working checkouts on different branches in different base directories.
But worktrees have some significant limitations. Not least of which is that their dependence on hardcoded fully-qualified paths written into configuration files not only makes worktrees non-portable, but also makes them DOA for any kind of containerized development environment. The worktree.useRelativePaths option…
Owning your server stack shouldn't be a source of anxiety. Unfortunately, it often is, especially if you only pay attention to the problems you can feel in your gut: Is the app running? Is it throwing exceptions? Does it seem fast enough? These are great intuitive measurements, but just as a doctor uses diagnostics to catch high blood pressure before it becomes a crisis, you need deeper visibility to detect memory leaks, CPU spikes, and disk consumption before they bring your project to a halt.
Hatchbox and AppSignal give you that "deeper visibility." They simplify infrastructure management by replacing manual monitoring with automated, real-time feedback. Together, they transform complex…
Mission:
remove friction,
not gates.
Use AI to speed research,
produce better first drafts,
and surface facts.
Never skip CI or reviewer sign-off.
- safer Rails changes
- repeatable reviews
- fewer context losses
- private memory that keeps improving
If it does not reduce mistakes,
turn it off.
The Old Way
The old workflow was simple:
ask a model a question
copy the answer
paste into editor
manually fix context gaps
repeat
That works for small tasks.
It breaks down for real Rails work.
The missing context is predictable:
- repo conventions
- ownership mapping
- migration review expectations
- mandatory checks before merge
The result is familiar:
Fixing a cryptic fetch error when installing a Ruby gem from a git repository.
People focus so much on <h1> and alt attributes that they forget about usability.
Introduction
When discussing accessibility (a11y), we all focus on the structure of our <h1>/<h2>, the alt image texts, the contrast,
and all the necessary rules to be covered. The problem is that during the process, we forget to think about usability:
Is the page saying what it is supposed to be saying? Does the image description reflect what you can see there? Or take
link text as an example: Does “Read More” explain what content the user is about to access?
Most of the time, usability is overshadowed by a focus on compliance with accessibility standards.
As a result, we end up with a site that passes…
Take a trip through Joël and Aji’s YouTube recommended list as they go over the media that has inspired their work the most over the course of their careers.
Our hosts highlight different creators that feature regularly in their YouTube rotation, the long standing channels that have had the most impact on them, the video essays that inspire their work, as well as a small detour Into the world of history videos.
—
Here’s a handful of Joël and Ali’s personal recommendations:
VSauce - Veritasium - Jet Lag the Game - The Coding Train - Tom Scott - Kings and Generals - Daniel Steiner - Assassin’s Creed: Echoes of History - Jay Foreman / Map Men - Practical Engineering - Hannah…
Your hosts for this episode have been thoughtbot’s own Joël Quenneville and Aji Slater.
If you would like to support the show, head over to our Gi…
Abstract 🔗
Congrats on joining Hours Unlimited. The Math and Numbers team is excited to have you join us on our journey to redefine the importance of numerals. This introductory session will provide tips and tricks for best interacting with powerfuLLMachine, the next-level platform we use to unlock productivity and effectiveness.
Presentation Resources 🔗
Reviews 🔗
@kevin_j_m’s talk is a must-watch! I laughed so hard it hurt, and then almost cried. A satirical review of the industry today, with a poignant plea for the future.
Kevin Murphy’s talk, InstiLLMent of Successful Practices in an Agentic World, started out funny. A hilarious bit about being…
When my Sidekiq job starts failing or slowing down, I often feel frustrated, especially if I don’t know how to fix it.
If you’re using Sidekiq to run your background jobs, you know what I’m talking about. It’s a vital element of your stack, handling everything from data exports to password reset requests. It runs silently in the background, and most of the time, you’re not even giving it a second thought.
However, when things go wrong, like pages loading slowly, emails never being sent, or exports failing, the impact can be huge. Getting to the bottom of the issue can be like finding a needle in a haystack.
That’s where AppSignal comes in. It can monitor your Sidekiq jobs, alert you when…
Authentication proves identity.
Authorization enforces rules.
Most production authorization bugs in Rails are not syntax mistakes.
They are missing tenant scopes,
global find calls,
or new controller actions that shipped without a policy check.
Rails 8.1.3 is current as of April 28, 2026,
and Rails 8 ships with a good authentication generator.
That solves only the first half.
After sign in,
we still need a clear rule for every sensitive read and write.
TL;DR
- Authentication is not authorization.
- Scope collections before loading records.
- Treat
Model.find(params[:id]) as suspicious in multi-tenant code.
- Use view checks only for display. Controllers and APIs still need policy…
The…
I built a private local AI brain so assistants start with my defaults,
not a blank prompt.
Generic assistants help,
but they do not know how I review Rails,
what I call risky,
or why I choose boring over clever.
It has three parts:
- a Karpathy-style LLM Wiki for durable knowledge
-
gbrain for my trained and distilled work signals
-
gstack for using that memory inside day-to-day coding workflows
The important part: the private corpus stays private.
I distill repeated patterns from my own data signals.
I am not retraining a public model on private work.
The raw work history, private comments, internal repo names, client names,
server paths, credentials, and customer details are not…
Rails gives us a strong security baseline.
It does not make an application secure by itself.
That distinction matters.
Most real Rails security issues are not caused by Rails forgetting to escape HTML.
They come from stale versions, missing authorization checks, exposed secrets,
unsafe admin workflows, weak session handling, and business logic that trusts the wrong user.
This guide covers what Rails protects by default,
what newer Rails versions add,
and what every production Rails app still needs to own.
TL;DR
- As of April 2026, Rails 8.1.3 is the latest Rails release.
- Rails 8.1 adds local CI and credential fetching that make security checks easier to standardize.
- Rails protects…
Spinel in Practice: What Works and What Breaks April 27, 2026 Built for Ruby on Rails Build Maps WithoutGoogle APIs Generate beautiful production-ready maps directly from your Rails backend. Fast rendering, zero external dependencies, full control. View Live Demo → Read Docs ✓ No API fees ✓ Self-hosted ✓ Rails Native ✓ Fast Rendering Why … Continue reading Spinel in Practice: What Works and What Breaks →
Since I wrote about async Ruby and patched Solid Queue to support fibers, people keep asking the same questions. What happens when a fiber blocks? Don’t you still need threads? What about database transactions? What about Ractors?
This post answers all of it. From the ground up.
The four primitives
Ruby gives you four concurrency primitives: processes, threads, fibers, and Ractors. They nest. Every process has an implicit “main Ractor” where your code runs by default, so you never have to think about Ractors unless you explicitly create one. Without Ractors, the hierarchy is simply process – threads – fibers. With Ractors, it becomes:
graph TD
P[Process] --> R1["Ractor 1 (GVL 1)"]
…
I recently joined ShopTalk Show… episode 711 to be exact. Which… now has me thinking I should probably go get myself a Slurpee.
A few things we got into…
-
Oh My Zsh started as shared aliases for teammates… and turned into a plugin ecosystem that keeps growing.
-
Ruby on Rails in 2026… scaling isn’t the question anymore. Teams are wrestling with restraint and keeping systems understandable.
-
LLMs and contribution… more people can open meaningful PRs now. Conventions and structure matter more than ever.
-
Dependencies… every one feels small when added. Over time… they stack up and stick around longer than expected.
If you haven’t listened to ShopTalk Show… go subscribe.
Every two years, the team at Planet Argon runs the Rails Developer Survey. And every two years, I go through the same process… a long list of questions, a hard look at how much time we’re asking of respondents, and a lot of cutting.
If you’ve filled it out before, thank you. If this is new to you, here’s the short version: it’s an open survey for Rails developers at all experience levels and across all kinds of organizations. We compile the results and share everything publicly. No paywalls. No vendor spin. Just a snapshot of what the community is actually doing.
We first ran this in 2009… back when ”should I use Rails?” was still a serious question… and have been doing it every two years…
It’s become…
AI is everywhere right now. New models, agents, and tools appear almost daily, each promising to
transform how companies work. But when teams come to us asking for help with AI, the challenge is
rarely how to build something; instead, the question is what to build, and whether AI is even the
right tool in the first place.
I was listening to an episode of the Super Data Podcast where Jon Krohn interviewed John Roese,
Global CTO and Chief AI Officer at Dell, and one moment stuck with me. They were discussing why so
many AI projects fail to move the needle inside organizations, and Roese put it succinctly: in
many cases, AI is being used to automate work that was essentially BS to begin with.
…
Let's talk about what's really going on.
Continue Reading
T-minus 4 days until we launch the new site! A lot of my work this week has gone towards that, alongside continued heroic efforts from Max, who, among other things, sorted out custom OpenGraph images for all our pages! It’s also been great to work with Aaron this weekend to get all our brand assets nicely sorted out. I’m excited! We’re going to be launching something really, really nice. Can’t wait to share it with you all in a few days.
I released Dry Monads 1.10.0 this week. This release introduces complete JRuby support thanks to fixes from Paweł to our RSpec extension. It’s also the first release we’ve directly published to our shiny new gem.coop namespace!
In fact, as of this week…
13 years ago today I released the very first version of Mustermann.
It allows you to create Regexp-like pattern objects:
require "mustermann"
pattern = Mustermann.new("/hello/:name")
pattern =~ "/hello/world" # => 0
pattern.params("/hello/world") # => {"name" => "world"}
This is what Sinatra uses to match routes and extract parameters from the request path.
Since then other projects besides Sinatra have started using Mustermann, which I think is fantastic, and it has been maintained by a great community of contributors over the years. I myself took a break from Mustermann from 2017 until two weeks ago!
Performance, performance, performance!
You can find the full list of…
A shorter companion piece to the latest RailsRevelry article on how Rails matches requests, extracts params, and dispatches controller actions.
The Rails Way in 2026
We had an interesting discussion at the Arkency weekly call today. The topic was how to define “the Rails Way” in 2026. The discussion branched in many directions, but I want to capture the result here.
We get to see a lot of Rails repositories. There’s a pattern that shows up so consistently that I think it now deserves to be called “the Rails Way” of 2026:
A fat model with a callback. The callback triggers a service object. The service object is executed as a background job.
That’s the clue of this post. If you zoom out across the Rails applications written or maintained in 2026, that’s the shape.
The disclaimer
A word about where we’re coming from. Arkency is a…
Hi, it’s Claudio Baccigalupo. Let’s explore what happened this week in Ruby on Rails.
Apply as a speaker for Rails World
Don’t miss out on the opportunity to join 1,200+ Rails developers this year at the Palmer Center, Austin, TX. Corporate Support tickets are on sale now. General admission tickets will be released on May 12.
How do you use Ruby on Rails?
The 2026 Ruby on Rails Community Survey is open! Takes just a few minutes. Please fill out and share with your team!
Bump required PostgreSQL version to 10.0
Until now Rails claimed support for PostgreSQL 9.3, which is incompatible with PostgreSQL 18 (released in 2025).
The pg gem v1.6 already raised its minimum required PostgreSQL.…
Why predicate-like checks on Active Record associations can quietly cross the database boundary.
Ruby Central Restructuring
This BREAKING NEWS episode is a candid reaction to Ruby Central’s latest shakeup, with Chris, Andrew, and David unpacking leadership departures, financial strain, the cancelled gala, and what all of it says about the organization’s direction. The conversation moves beyond the headlines into bigger questions about trust, transparency, community values, conference strategy, RubyGems sustainability, and whether Ruby Central can rebuild credibility by involving more of the community in what happens next. Hit download now to hear more!
Links
HoneybadgerHoneybadger is an application health…
Your hesitation before a big software project might be the strategy.
Continue Reading
You gave a handful of your devs access to Claude Code Max… and things moved fast. Output went up. Then things started to drift. Not just formatting or naming. Structure. Approach. Assumptions. One developer builds guardrails around it. Another uses it like autocomplete. A third treats it like a thinking partner. Same tool, same codebase… different results. The code starts to reflect how each person uses the tool, not how the team builds software together.
There’s a tension here that most teams are sidestepping. You can feel the inconsistency creeping in, but saying “we should align on how we use this” sounds heavy-handed. So it gets framed as experimentation. Let people figure it out. Give…
Hi everyone! Rails World is back heading to Austin, Texas on September 23-24, 2026 for the largest Rails World yet, with space for 1,200 developers, founders, and teams building with Rails, and we have a huge Rails World update for you!

First: The Rails World website is finally live thanks to our website sponsor WyeWorks, and the amazing work of developers Jessica Ferreira and Lucas Troncoso and designer Jomiro Eming. Big thanks to the team!
Check it out.
Apply to speak at Rails World 2026
Most of all, we’re excited to announce that the CFP for Rails World 2026 is officially open.
Submit your talk by May 16: https://sessionize.com/rails-world-2026/
What we’re looking for in 2026…
#797 — April 23, 2026
Read on the Web
Ruby Weekly
JRuby 10.1 Released with Ruby 4.0 Compatibility — The first major release of the popular JVM-based Ruby implementation “since catching up with Ruby compatibility” gets Ruby 4.0 compatibility and shifts to a biennial LTS release cycle. There are memory improvements too: every object is 8 bytes smaller, plus tighter numeric representations.
Charles Oliver Nutter
Memetria K/V: Efficient Redis & Valkey Hosting — Memetria K/V hosts Redis OSS and Valkey for Ruby apps, featuring large key tracking and detailed analytics.
Memetria sponsor
A New…
JavaScript errors (either vanilla or with Stimulus controllers) often happen silently in the browser, leaving your users confused about what went wrong. “Why did nothing happen?”. “I just did click the button!” “Let’s try again…”. Still nothing… Starts furiously clicking the button now.
This poor user experience can be frustrating and can lead to more support tickets that could have been prevented. In this article I want to show how to build a simple class that catches unhandled JavaScript errors and displays them to the user in a friendly banner. It’s a small but meaningful improvement to your app’s user experience.
As always, the code can be found on GitHub.
The silence of the errors
Whe…
MapView Flyers are at RubyKaigi 2026 – Here's the Must-Watch Talk Schedule April 22, 2026 Scan to try
Live Demo Available Introducing MapView Render beautiful, production-ready maps directly from your Ruby backend. No external APIs. No dependencies. Just pure speed and control. ✓ Zero external dependencies ✓ Lightning-fast rendering ✓ Production-ready & battle-tested Try … Continue reading MapView Flyers are at RubyKaigi 2026 – Here’s the Must-Watch Talk Schedule →