I’ve built many a SaaS. And most have pricing tiers: the higher the plans the more widgets you can create or features are allowd. Typically there are two ways to approach this:
- hide the feature if the customer does not have access;
- show all features, to all customers, but guard them with some, optional, upsell.
I have succesfully implementated the latter approach with a helper that quacks like Rails itself.
The helper lets you wrap content and decide what happens when access is denied. Hide it, redirect to a link, render content or render a partial. It’s small but flexible. This is how it looks (added a toggle allowed/denied states):

As always view on GitHub for a ready-to-copy code.
The…
Why Ruby's Issue Tracker Still Links to a 1991 Paper About Floating-Point Numbers July 8, 2026 If you've ever been surprised by this in Ruby: (2.0 - 1.1) == 0.9 # => false you're not alone. Many developers initially assume this is a Ruby bug. It isn't. In fact, Ruby's own issue tracker includes a … Continue reading Why Ruby’s Issue Tracker Still Links to a 1991 Paper About Floating-Point Numbers →
I was recently a guest on Scaling DevTools, hosted by the gracious Jack Bridger.
We talked about how Oh My Zsh went from a messy little config I shared with a few coworkers into one of the more widely used open source developer tools in the world. Which still feels a little absurd, especially when I look back at the original blog post where I announced it and remember how little grand strategy was involved.
The original goal was not world domination. There was no developer platform strategy. No roadmap. No monetization funnel wearing a fake mustache.
As I said in the conversation:
I literally wanted, like, eight of my coworkers to have this on their computer so that I could be lazy…
One of our all-time clients owns a multi-brand marketplace. Earlier this year, he had an idea to revolutionize his platform by observing how his users behave and turning that information into actionable insights for his customers (the brands). The core idea was to track user events, turn each user’s events into a single, computed profile that identifies them (internally called a fingerprint), and use this information to build a brand brief, including user segments and actionable insights.
For this project, our client wanted to use AI throughout the development process: he built the plan with AI assistance, designed the UI with AI, and planned to use AI for most of the features he wanted to…
You may not be aware that, since Rails 7.1, the standard way to store secrets is by using credentials.yml instead of the old secrets.yml.
DEPRECATION WARNING:
`Rails.application.secrets` is deprecated in favor of `Rails.application.credentials`
and will be removed in Rails 7.2.
If you still see this warning, your app uses secrets.yml and the migration applies to you. If you don’t use Rails.application.secrets or config/secrets.yml at all, you can ignore the deprecation and the rest of this post.
The migration itself isn’t hard, but it can take some coordination: if your app runs in several environments, you’ll probably need to work with whoever manages your servers to move everything…
Authors: Gleb Stroganov, Product Designer, Camila Mirabal, Tech writer, and Travis Turner, Tech Editor
Topics: AI, Design, DX, Design engineering, Agent Experience, Design for devtools, Agentic development

Storybook Workbench is a bundle of Agent Skills that turn Storybook into an audit layer for AI-generated UIs: find dead components, design-system drift, and hidden accessibility bugs.
An AI agent can generate a full web app that looks plausible and runs within one afternoon. However, you still can’t really tell which of the 469 component files in ‘src/’ are structural and which are dead ends the agent abandoned three prompts ago. So, Evil Martians built Storybook Workbench: a set of agent…
This is episode #04 of the Ruby Stained Glass Notes, a pop-up newsletter in which I write about the process of building a stained glass panel celebrating Ruby. Today, I talk about tools!
What happens when your entire app rests on one developer's shoulders?
Continue Reading
Fullscript is sponsoring the Relax Lounge at RubyConf this year; it’s the conference experience that felt like the right fit.
The Ruby community has given us a lot; not just the tools we build on, but the people and community who've shaped how we work. Our folks attended Ruby conferences in five countries last year, and we continue to support meetups across North America. We keep showing up because we've seen what happens when devs actually get in the same room. Things click differently in person. There's something about face-to-face that you can't replicate over Slack.
So when RubyConf came around we asked ourselves what we could contribute that felt like us. We're a healthcare company:…
Judoscale ‘On Tour’ Series
- “The Friction Model” & Heroku
-
Render (This page!)
-
Railway (Coming soon…)
-
Fly (Coming soon…)
-
Northflank (Coming soon…)
-
Digital Ocean (Coming soon…)
-
Amazon ECS Fargate (Coming soon…)
After about a month of migrating, tweaking, and configuring, our opinions are in! We successfully migrated our full production and staging application stacks to Render. We tried as many bells and whistles as we could, let things run for a non-trivial amount of time, and have some interesting thoughts to share with you.
👀 Note
The “Judoscale Tour” is our exploration of today’s PaaS offerings via deliberately migrating our real production app, our…
The Rails Foundation is looking for two people to be MCs at Rails World this year, and we think that some of the best candidates are already doing the job every month in Ruby communities around the world…
Ruby User Groups (RUGs) are where people find their first Ruby friends, give their first talks, discover their next role, and become part of the community, and RUG organizers are a huge part of what makes the Ruby ecosystem special. They create welcoming spaces, introduce speakers, keep events running smoothly, and make newcomers feel at home — all the things that make a great Rails World MC too.
That’s why, this year, we’re inviting RUG organizers from around the world to apply to be a…
Sally and Joël join forces to discuss the different ways to interpret the role of a ‘principle’ or ‘staff’ engineer, and the handwaving around what those titles mean in terms of the gradation.
Whilst Joël dives into career progression within the industry, what a staff engineer does and the different archetypes within it, Sally talks about the importance of having principle engineers in the room during AI discussions, and her previous positive experiences working with principle engineers.
—
Joel used the Staff Archetypes page from staffeng.com during this episode’s discussion.
Your hosts for this episode have been thoughtbot’s own Joël Quenneville and Sally Hall.
Don't forget…
You ship a new background job—let’s call it SendShinyNewThingJob—run the deploy, and go get coffee. By the time you’re back, the error tracker is on fire:
NameError: uninitialized constant SendShinyNewThingJob
But the class is right there in the codebase. It’s deployed. You can call SendShinyNewThingJob.perform_later in a console on production without a hitch. So what happened?
Why a class you just deployed is “missing”
The culprit is the rolling deploy. When you roll out a new version, old and new processes run side by side for a while—that’s the whole point, zero downtime. During that window you have two kinds of processes in play:
- something that enqueues jobs: a freshly started…

Version 6.1.7 of the Passenger application server has been released. This release addresses an ABI break in EL9 (RHEL/Rocky/Alma) Nginx packages.
Installing 6.1.7
Please see the installation guide for advice on getting started with Passenger. Coming from a language other than Ruby, Python, Meteor or Node? Even if we didn't write a specific tutorial for your language, we made a generic guide that shows you the steps.
Upgrading to 6.1.7
We strongly advise staying up to date with the latest version.
Check out our upgrade guides for the different platforms:
Please be aware that you can enjoy enterprise features and sponsor the open source…
Ruby JSON is a JSON implementation for Ruby. Versions 2.9.0 through
2.19.8 are vulnerable to heap buffer overflow when the JSON generator
is provided with an oversized streamed object.
When streaming to an IO JSON.dump(obj, io) and JSON::State#generate(obj, io)
can write past the internal JSON generator buffer when a streamed
object contains an attacker-controlled string near 16 KB. Exploitation
would result in a reliable process crash/denial of service.
This was triaged on HackerOne as report #3785370.
The issue was confirmed there and I was asked to open it here.
This issue has been fixed in version 2.19.9.
ruby webrick through v1.9.2 WEBrick reparses trailer Content-Length
into canonical request state, enabling request smuggling.
Now that I’ve been working on Spinel Cooperative for a full year already, I have finally managed to write the very first post I meant to write about the entire situation: What is Spinel? Who is Spinel? Why is Spinel? Read on to finally receive the answers to all these and questions and more.
Head over to the Spinel Cooperative blog to read Meet Spinel.
Hanami 3.0 is out! In this writer’s opinion, a release worthy of its new major version: new mailers, i18n, and Minitest, your apps becoming way faster, and much more!
I’m proud of this release. Eight months of continuous work. Two brand new gems. 100 pull requests authored by me, another 50 by our team and community. I feel we’re getting better and better with how we bring improvements and polish to Hanami and the Hanakai ecosystem.
I didn’t manage my last couple of weeknotes due to the focus I needed to put on the release. To sum it up: I prepared and pushed a release candidate, wrote substantial new docs (in particular, mailers, internationalisation, logger, container and components),…
Turning a Claude skill audit report into a labelled, severity-tiered GitHub backlog, and what the skill found in a small Rails 8 app.
In this episode, we look at creating Claude slash commands. These can be useful when dealing with a complicated task or trying to extract certain information from the application.
## Summary
The `Pay::Webhooks::PaddleBillingController#valid_signature?`
(`app/controllers/pay/webhooks/paddle_billing_controller.rb`)
verifies the Paddle Billing webhook signature by computing
`OpenSSL::HMAC.hexdigest(...)` and comparing it to the attacker-supplied
header value using Ruby's `String#==`. Ruby's `==` is non-constant-time —
it returns as soon as the first byte mismatches — and exposes a per-byte
timing side channel on the webhook signature verification path. The
canonical mitigation is to use a constant-time primitive
(`OpenSSL.fixed_length_secure_compare` /
`ActiveSupport::SecurityUtils.secure_compare`).
- IMPACT - CWE-208 — Observable Timing Discrepancy on the webhook
…
A quick look at how TypeScript conditional types behave with union types.
developers in Learning & Belonging cultures, who endorse a “coding is learnable” set of beliefs, experience this moment very differently. Their identity threat was cut in half.
Mastodon: @grimalkina@mastodon.social
Observability is the capability to understand the internal state of a system purely from its outputs. Rather than instrumenting every internal component or requiring deep knowledge of how a system is built, a well-observable system lets you monitor, reason about, and understand what’s happening inside just by examining what comes out. Think of it as the difference between opening up an engine to diagnose a problem versus reading the dashboard.
What is Observability for LLM Applications?
In practice, observability rests on three pillars: logging records discrete events as they happen; metrics track aggregated measurements over time; and tracing follows the flow of a request as it moves…
Hi, it’s Emmanuel Hayford. Let’s explore this week’s changes in the Rails codebase.
Make add_foreign_key(if_not_exists: true) reversible
Inverting add_foreign_key ..., if_not_exists: true produced remove_foreign_key ..., if_not_exists: true:
recorder.inverse_of(:add_foreign_key, [:articles, :authors, if_not_exists: true])
# => [:remove_foreign_key, [:articles, :authors, {if_not_exists: true}], nil]
remove_foreign_key does not understand :if_not_exists, so rolling back such a migration was not the idempotent inverse of the addition. The fix translates :if_not_exists into :if_exists when inverting, exactly as invert_add_check_constraint already does:
# => [:remove_foreign_key,…
Over the past year and a half, the Rails Foundation has partnered with Chris Oliver to create a set of tutorials designed to help new developers build a real-world Rails application step by step. Beginning with the original Getting Started Guide, the series guides learners through the core concepts of modern Rails development by building an e-commerce application, adding common features along the way such as user authentication, user and admin settings, and creating wishlists.
Today, the series is complete with the newest tutorial: Product Reviews.
In this tutorial, learners will build on the previous Rails application by adding product reviews. You’ll learn how to:
Chris Is Back And Ready To Rant
Chris returns from Greece and catches up with Andrew and David on travel, conferences, movies, and the latest developments in the Rails community. They dig into the newly announced Rails World lineup, the possibilities of Active Search, alternatives to Elasticsearch, extending Action Text and Lexi, a tricky ruby-vips dependency update, and mise’s rapidly expanding machine bootstrap tools. They wrap up with open source funding, RubyConf preparations, rising tech prices, and the massive anticipation surrounding GTA VI. Hit the download button now!
Links
I’m pleased to announce the release of Extralite 3.0.0. This release marks the
addition of object graph transforms, the transition to modern defaults for
opening SQLite databases, and a minor security enhancement.
Extralite is a fast and
innovative SQLite wrapper for Ruby with a rich set of features. It provides
multiple ways of retrieving data from SQLite databases, makes it possible to use
SQLite databases in multi-threaded and multi-fibered Ruby apps, and includes a
comprehensive set of tools for managing SQLite databases.
Object Graph Transforms
In the last few years I’ve been transitioning from using an ORM (such as
ActiveRecord) as a database abstraction to a more explicit, less…
July 2, 2026 Modern applications rarely consume external data exactly as it arrives. Whether you're integrating with payment gateways, CRMs, ERPs, or third-party APIs, incoming payloads almost always need to be normalized, enriched, or reshaped before they can be processed. A common workflow looks like this: Incoming Payload │ ▼ Transformation Layer │ ▼ Normalized … Continue reading How to Safely and Efficiently Transform Payloads in Ruby and Ruby on Rails Workflows →

One of the things that makes our community special is the way people keep showing up for each other.
Recently, a member of our community found themselves unable to attend RubyConf 2026 and generously offered to donate their ticket so that someone else could have the opportunity to join us in Las Vegas.
That act of generosity sparked a bigger idea among another community member.
We know there are Rubyists who would love to attend RubyConf this year but are facing budget constraints. Whether it's competing conference budgets, travel costs, or simply a challenging year financially, we don't want cost to be the only thing standing between someone and the people, ideas, and opportunities waiting…
#807 — July 2, 2026
Read on the Web
Ruby Weekly
What Active Rubyists at RubyKaigi Are Using in 2026 — RubyGems's maintainer shares data based upon a survey of RubyKaigi 2026 attendees. It's an interesting sample, as RubyKaigi attendees tend to be active shippers, maintainers, and prominent Rubyists. Ruby 4.0 usage is strong, VS Code dominates, and most are using Claude Code and Docker Compose.
Hiroshi Shibata
💡 On the topic of surveys, the 2026 Ruby on Rails Community Survey closes tomorrow, so take it now if you can.
Rails Experts You Like & Trust, Now Embedded in Your Team 🚀 — Since '17, companies have trusted…
Changelog widgets, like those from Headway and Beamer, are still a popular way to tell your users about updates to your product. What if you could build one yourself?
Perron, the Rails-based SSG, has a library of production-ready custom elements. One of them, the Embed Content component is perfect for this exact use case. It fetches JSON data, renders it as a list, tracks read state and handles all the UI interactions. You just provide the data.
The result will look like this:

Pretty smooth, right?
Most changelog services lock you into their platform. You pay per seat, deal with their branding and accept their feature set. If you want something simpler or more tailored to your product,…
Dependabot Resolves Remaining Bundler 4 Compatibility Issues July 1, 2026 Teams adopting Bundler 4 can breathe a little easier. After several weeks of community reports and investigation, the remaining compatibility issues between Dependabot and Bundler 4 have now been addressed through merged fixes in dependabot-core. The fixes resolve two separate issues that affected projects relying … Continue reading Dependabot Resolves Remaining Bundler 4 Compatibility Issues →
What you spend your time on is what you practice, and what you practice is what you build skill on. If the work is shifting to supervision, then that’s the craft now. We’re building the machine that builds the machine. And it deserves the same investment in tooling, practice, and professional development that we gave the inner and outer loops before it.
Annie Vella: The Middle Loop
This article shows the compatibility between Sidekiq and Rails across different versions. Even though Rails is not a dependency of Sidekiq, there are compatibility considerations for different combinations given that Sidekiq provides integrations with Rails.
If you need help with Sidekiq’s compatibility with Ruby, check this other article instead.
Rows highlighted in red, below, indicate Rails versions that have reached the end of their security support.
Rails Versions
Sidekiq Version
8.x
>=
8.0.0
7.x
>=
6.5.10
and
>=
8.0.6
6.x
>=
6.0.0,
…
Many Rails teams that we have worked with have a version of the same story: a test suite that grew organically, was never quite prioritized, and now sits somewhere between “unreliable” and “actively avoided.” Maybe tests are slow. Maybe they’re flaky. Maybe coverage gaps makes deployments feel like a roll of the dice. Or a manual battle against a behemoth of a beast. It is likely you have heard engineers gripe about the test’s reliability and may be worried that they are sinking time in the application.
Improving your test suite is one of the highest leverage investments a development team can make even though it’s often deprioritized. While the benefits are not always obvious to those…
It's more complex than just evaluating output.
Continue Reading
Developer happiness has never been about smiling at your keyboard. It is about clarity. It is about friction being low enough that you are not constantly fighting your own tools. It is about expressiveness so your intent stays visible when you come back six months later. Those principles are not decorative. They are survival strategies.
Obie Fernandez: Ruby Was Ready From the Start
Ruby has always encouraged us to think about design as something you live inside, not something you should add later or simply ignore.
Obie Fernandez: Ruby Was Ready From the Start
Authors: Victoria Melnikova, Head of New Business, Host of Dev Propulsion Labs, and Travis Turner, Tech Editor
Topics: AI, Design, Developer Community, Design for devtools

Evil Martians went from attempting to one-shot AI illustrations to a human-in-the-loop workflow with a dedicated illustrator. When a human owns first and last mile of this process, illustrations are crisp, high-quality and fun. Go BTS of our illustration production.
Evil Martians take huge pride in our blog. Illustrations are there to support the vision. We fantasized that image gen tools are ready for us to one-shot illustrations, but we were wrong. Instead we built a process where blog editor owns the first mile, AI does…
Server Sent Events (SSE) allows a server to push data, one way, to a client over a long lived HTTP connection without the client needing to make multiple requests. Even better, the client will automatically reconnect if the connection drops. Here’s a few use cases that SSE is great for:
Implementing SSE is fairly trivial in Ruby especially when using Rack 3.0.0 middleware and htmx on the front end so let’s explore further by diving into the code!
Quick Start
If you’d prefer to have all of…
With AI seeming to generate more code every day, we need better tools to verify that it hasn't broken something. Maybe mutation testing can help us get there. Markus Schirp chats with us about the mutant gem and mutation testing.
Show Notes
Sponsors
Lots of teams out there are still overpaying for their hosting and getting tripped up by traffic spikes. If you’re on one of those teams, you need a better autoscaler. Judoscale uses better metrics, gives you more control, and reacts faster than any other autoscaler. Learn more at https://judoscale.com/
From the very beginning we set out to make Hanami a different kind of Ruby framework: clear, modular, and built to grow. Today it comes into full bloom. We’re thrilled to share Hanami 3.0 with you!
This release rounds out the framework with three big new features: mailers, internationalization, and Minitest. On top of that, your apps are now faster by default, and your developer experience is sharper, from your logs all the way to your assets.
First-class mailers
Our long lost gem is back! Hanami apps now come with integrated mailers, which feel right at home next to your actions, views, and operations.
Mailer classes describe everything you need to deliver an email:
Design Patterns, the Ruby Way (Part 3): Behavioral Patterns in Real Ruby Applications June 30, 2026 In the previous article, we explored how Ruby simplifies many creational and structural design patterns. But some of the most interesting patterns aren't about creating or organizing objects. They're about how objects collaborate. Behavioral patterns define how responsibilities are … Continue reading Design Patterns, the Ruby Way (Part 3): Behavioral Patterns in Real Ruby Applications →
By default, wins get trumpeted in one setting (blog posts, conference talks, all hands) and costs bubble up in others (SRE team meetings, on call, retros, complainy DMs, grumbling over whiskey).
The result is that both sides may feel like they are being unfairly silenced.
Charity Majors: AI Enthusiasts Are in a Race Against Time, AI Skeptics Are in a Race Against Entropy
Authors: Evgeniy Valyaev, Frontend Engineer, and Travis Turner, Tech Editor
Topics: AI, DX, LLMs

An MCP server is a product interface for the age of agents, not an AI feature itself. This post presents a framework for deciding between direct API calls, CLI, Skills, and MCP, detailing the architectural signals, the hidden costs, and the failure modes you should know about before embarking on an MCP quest.
Most MCP servers are not agent architecture, but premature product interfaces. The first hype wave produced too many half-baked implementations because a lot of products simply don't need an MCP server. Instead, sometimes direct API calls are enough. For some, a CLI does the job. For others, a…
We built an automated event aggregation platform, ingesting events from hundreds of partner venues, arts organizations, and ticketing platforms into a single searchable index. Every partner has a different website, a different structure, and a different set of rules for where event data lives.
We could not hand-craft scrapers for each one. So we built a system where an AI generates the scraping rules, validates its own output, and corrects itself when it gets things wrong.
This post covers what we learned: the real challenges of AI-driven scraping, the strategies that worked, and the ones that didn’t. This post does not cover the architecture of the platform or the system design of it.
…
Aji is joined by thoughtbot’s own Tess Griffin and Jimmy Thigpen, two members of the recently established AI Ethics Taskforce, to talk about what kind of conversations are going on in the company around AI.
With AI becoming an omnipresent entity in the industry, Tess and Jimmy take a deep dive into how and why the taskforce got started, figuring out what thoughtbot’s stance is around AI in terms of ethics and workflows, and how it relates to their clients.
—
As mentioned in the episode:
Blastoff Rails June 11 - 12, 2026 (past) Albuquerque, New Mexico
Freddy discovers America during the World Cup
Your guests for this episode have been Tess Griffin and Jimmy Thigpen and your…
A short invitation to RailsRevelry, a focused publication for Rails developers who want clearer mental models of how the framework behaves.
Ruby 3.4.10 has been released.
This release is a regular stable package release contains the version update of bundled gem net-imap. The net-imap.gem update contains some security fixes. Please see the release note of net-imap v0.5.15 for the detailed update of net-imap.gem.
Please see the GitHub releases for further details.
Download

At Gusto, one of our core values is being customer obsessed. That means meeting customers where they are and ensuring they get the right support at the right time.
A few months ago, we needed to ship a system that could seamlessly hand customers off from our AI assistant to a human agent, one that could proactively gauge customers’ needs and escalate in a timely manner, helping maintain trust and a good customer experience. There was a clear opportunity to improve the AI-to-human escalation experience, but the rules and criteria were still evolving across teams.
The old playbook for building machine learning (ML) systems is pretty straightforward: collect data, train a model, then deploy. But…
I’ve been writing ruby and rails for nearly 20 years. A couple weeks ago, I had gotten code snippets from copy-paste in a chat window, but I hadn’t even experimented with Claude Code or similar “can write code to your file system” tools.
I know some people are now using LLM’s to write all their code, which I’m not excited about, but I decided I couldn’t hold off any longer, and I had to at least understand how it worked to be able to decide when/where to use it. Everything in here is probably (?) old news for people already way into using LLMs to write code.
I decided that a project to speed up my rspec test suite (using the amazing test-prof for profiling and performance…
Design Patterns, the Ruby Way (Part 2): Modern Creational and Structural Patterns June 28, 2026 In the first article of this series, we explored why Ruby changes the way developers think about design patterns. Features like duck typing, modules, blocks, and delegation often replace the ceremony required in more rigid object-oriented languages. Now it's time … Continue reading Design Patterns, the Ruby Way (Part 2): Modern Creational and Structural Patterns →
## Summary
YARD's static cache lookup reads a request path before the router's
path cleanup runs. When a server is configured with a document root,
a traversal path such as `/../yard-cache-secret.html` is joined
against that root and can return a readable sibling `.html` file
outside the intended static tree.
The potential security risk seems low, as only html-ending files can
be read, but still the risk of reading arbitrary html files is a
confiendtiality issue in itself, which is why we decided to report.
Please let us know if this is out of your project's scope.
"The `fluent-plugin-s3` plugin (specifically the `in_s3` input plugin)
supports reading and decompressing heavily compressed files (such as
`gzip`, `lzma2`, and `lzop`) from Amazon S3. It was discovered that
the plugin read the entire decompressed payload into memory at once
without enforcing a strict size limit.
If an attacker has sufficient permissions to upload files to the
monitored S3 bucket, they can upload a maliciously crafted, highly
compressed file. When Fluentd attempts to decompress this file, it
will expand to an excessive size and it will consume significant
system resources.
## Impact
This vulnerability allows for a **Denial of Service (DoS)** attack
via memory exhaustion.…
The `fluent-plugin-opentelemetry` plugin (specifically the
`in_opentelemetry` HTTP input) lacked strict size limits on incoming
requests. It was discovered that the plugin read the entire request
body and decompressed payloads into memory without enforcing maximum
size thresholds. If the OpenTelemetry ingestion endpoint is exposed to
untrusted networks, an attacker can send an excessively large HTTP
request or a maliciously crafted, highly compressed payload.
When the plugin attempts to read or decompress this payload, it will
expand to an excessive size and it will consume significant system resources.
### Impact
This vulnerability allows for a **Denial of Service (DoS)** attack
via…
## Impact
Crass recursively parses CSS simple blocks and functions without a
depth guard. An attacker-controlled value containing many deeply
nested blocks can recurse until Ruby raises SystemStackError:
stack level too deep, or can cause excessive memory usage.
## Impact
Crass converts CSS scientific notation number values with unbounded
exponentiation before it clamps the result to Float::MAX. Applications
that use Crass to parse attacker-controlled CSS strings can be forced
to spend disproportionate CPU and memory parsing a tiny input,
possibly resulting in a crash.
Exponents are now bounded before 10**exponent is computed.
## Impact
When parsing an input containing non-ASCII characters, inefficiencies
in how Crass tracks the positions of multi-byte characters result
in superlinear parsing time. An attacker-controlled input consisting
of many non-ASCII characters could cause excessive CPU consumption
and potentially denial of service.
## Impact
When the :preserve_comments option is not enabled (which is the
default behavior), Crass discards CSS comments by recursively
consuming the next token. An attacker who provides a stylesheet
containing a very large number of adjacent comments can cause
excessive recursion and trigger a SystemStackError.
Fluentd allows dynamically constructing file paths using the `${tag}`
placeholder. It was discovered that validation for this placeholder
was insufficient.
If a Fluentd instance is configured to receive logs from untrusted
sources and uses the `${tag}` placeholder in file configurations
(such as the `path` parameter in the `out_file` plugin), an attacker
can inject path traversal characters (e.g., `../`).
When combined with certain formatting options, this vulnerability allows
an attacker to write arbitrary files or overwrite existing files on
the system with attacker-controlled content, bypassing intended
directory restrictions.
### Impact
This vulnerability allows for **Arbitrary File…
Fluentd's Monitor Agent plugin (`in_monitor_agent`) exposes internal
metrics and plugin information via a REST API.
It was discovered that the API response (`/api/plugins.json` and
related endpoints) unintentionally includes internal instance
variables of loaded plugins.
If any plugins store sensitive information—such as database passwords,
API keys, or cloud credentials—in its instance variables, this
information may be exposed in plain text to any user or system
that has HTTP access to the Monitor Agent API.
### Impact
This vulnerability allows for unauthorized information disclosure. An
attacker who can reach the Monitor Agent API port (default: `24220`)
can potentially extract…
Fluentd's `in_http` and `in_forward` plugins support receiving
gzip-compressed data.
While Fluentd correctly enforces size limits on the incoming
compressed payloads (e.g., via `body_size_limit` or `chunk_size_limit`),
it was discovered that there is no limit enforced on the size of the
decompressed data. If a Fluentd instance is exposed to untrusted
networks, an attacker can send a maliciously crafted, highly
compressed payload. When Fluentd attempts to decompress this payload
in memory, it will expand to an excessive size, completely bypassing
the intended payload size limits.
### Impact
This vulnerability allows for a **Denial of Service (DoS)** attack
via memory exhaustion. The rapid…
The `out_http` output plugin allows the use of placeholders (such as
`${tag}`) in the `endpoint` configuration parameter. It was discovered
that if the placeholder value is derived from untrusted user input,
an attacker can maliciously control the destination hostname of the
outbound HTTP requests made by Fluentd.
## Impact
This vulnerability allows for a **Server-Side Request Forgery (SSRF)**
attack. An unauthenticated attacker can force the Fluentd node to send
HTTP requests to arbitrary internal services. This can lead to
unauthorized access to internal APIs, data exfiltration, or the
compromise of cloud metadata endpoints (e.g., AWS IMDS `169.254.169.254`).
Hi, it’s Vipul. This week was heavy on fixes: config parsing, association edge cases, caller-owned state, and more Ractor safety.
Add RFC 9110 compliant Accept header content negotiation opt-in
New opt-in: config.action_dispatch.respect_accept_header_rfc9110. Default: off.
Enable it when you want RFC-compliant media type specificity and quality handling, for example Accept: application/json, */* returning JSON.
If your app relies on old browser-like fallbacks, leave it off until you test real browser Accept headers in your app and CI.
Strip inline comments from unquoted dotenv values
Unquoted dotenv values now strip whitespace-prefixed inline comments before interpolation and command…

Version 6.1.6 of the Passenger application server has been released. This release updates the Nginx used in Passenger standalone and also addresses an ABI break in RHEL/Rocky/Alma Nginx packages.
Installing 6.1.6
Please see the installation guide for advice on getting started with Passenger. Coming from a language other than Ruby, Python, Meteor or Node? Even if we didn't write a specific tutorial for your language, we made a generic guide that shows you the steps.
Upgrading to 6.1.6
We strongly advise staying up to date with the latest version.
Check out our upgrade guides for the different platforms:
Please be aware that you can enjoy ente…
This is episode #03 of the Ruby Stained Glass Notes, a pop-up newsletter in which I write about the process of building a stained glass panel celebrating Ruby. Today, I riff on the drawing and ask you which version you prefer!
I've started moving all of my content over to baweaver.com powered by Bridgetown under github.com/baweaver/portfolio.
Why?
I wanted more control of my content and some of the mechanics around it, and to finally redo my homepage which I had not honestly updated since... 2014?
After years of attempts I landed on a design that I liked, and over vacation I had enough time to get it all put together.
Lemurs?
The current site is focused more on architectural imagery, watercolor, and art deco. Where are the lemurs then?
Well for those I want to make something more special, and I haven't quite figured out how I want to land that yet.
The current idea is a literal…
One of the ways I have been using coding agents these days is to prototype small UI changes in an existing project. I use them as a tool to explore.
In this usage mode, I am not interested in the code. I am interested in how the options look. My objective is to extract ideas from the LLM, choose what I want, and later work on the real change in a different chat.
Ask for a selector to compare
One little trick I discovered recently is that you can simply ask for a selector to compare the options.
The coding agent can implement several UI alternatives and add a small selector that lets you switch between them in the real application.
You can literally ask for it. This is a translation of…
Beam Up is a command-line tool I wanted for some time. Its goal is to make deployments of static sites across various providers simpler from your machine: run one command: beam_up ./output/. ❤️
If you feel generous, head over to the GitHub repo and give it a star! 🌟
Installation and configuration
To install Beam Up, run:
gem install beam_up
Then initialize a configuration file for your chosen provider with:
beam_up init # to start an interactive process, or:
# beam_up init hetzner
This creates a .beam_up.yml file:
provider: netlify
netlify:
api_token: your_token_here
project_id: your_project_id
Ready to beam ⚡
Now you can deploy your static site using the super fun beam_up command:
…
Users don’t experience systems as implementations. They experience them as continuity.
leaflet.pub: UI Is a Conservation Layer
Welcome to Once a Maintainer, where we interview open source maintainers and talk about the work they do.
This week we’re talking to Mike Dalessio, longtime Ruby maintainer (nokogiri, loofah, mechanize to name a few) and member of the Rails Committer team. Mike works on security, infrastructure, and performance at 37signals.
Once a Maintainer is written by the team at Infield, a platform for managing open source software upgrades.
I’d love to get started by hearing how you got into software development. What was your first exposure to writing software?
When I was a kid, I had a friend who lived up the street whose dad bought him a VIC-20, which was like the Commodore 64 predecessor. And we…
I think we wrote a brilliant critique of ideology. We should have completely blown [techno-optimist capitalism] out the water, but it of course just carried on. … material reality is more important if it offers to triple your wages. Co-option is easy. … Critique is important. I’m not dissing it. We should do it. But we shouldn’t have any illusions that it will make any difference without our words being turned into action.
wedontagree.net: Technically Radical: On the Unrecognized Potential of Tech Workers and Hackers
As much as I fear the fallout of this technology, I fear the fallout of ideological purity even more. Time and again, people fall victim to the transformation of a stance on an issue into a holy cause, a flag to rally behind, a group from which to exclude The Other. Purity is a dangerous idea—historically, more dangerous than technology’s capacity to change labor.
taggart-tech.com: I Used AI. It Worked. I Hated It.
the markets can stay irrational longer than you can stay solvent.
Gil Duran: Attack of the Trillionaire
At RubyConf 2026, anyone who buys a ticket before July 1st is entered into a raffle for an exclusive RubyConf VIP experience. What exactly is a RubyConf VIP experience?
Five lucky winners, drawn at random, will:
- Get a ticket for you and a plus-one to the world-famous RubyConf speakers' Dinner, where you'll meet your real-world Ruby Heroes. Get exclusive behind-the-scenes access to the people who make Ruby and make RubyConf while you eat like royalty.
- VIP reserved seating for all keynote talks so you won't miss a thing. No fighting for a free seat or squeezing in the middle of a row of strangers. Walk right up and take a load off.
- A personal "thank you" from the board and staff. Because we…
But that's not all, everyone who enters by buying a ticket by July 1st will receive a limited edition RubyConf 2026 pin! If you were on the fence before, don't let this chance of a lifetime pass you by. When the clock strikes midnight on July 1st (PST), this door will officially be closed. Anyone who buys a ticket after that will…
If you're heading to RubyConf this July, make sure to stop by and meet the team from SmartFinancial.
SmartFinancial is a technology-driven insurance marketplace that helps people find and compare insurance options across all 50 states. Their goal is simple: make buying insurance easier, more transparent, and less frustrating for consumers.
Ruby plays a major role in making that happen.
The SmartFinancial engineering team has been building and operating Ruby on Rails applications for years, and they're excited to be part of the RubyConf community in Las Vegas this July 14–16 at Red Rock Casino Resort. Like many of us, they're coming to learn, share ideas, meet fellow Rubyists, and stay…
The fifth obstacle is us. Our cynicism, our exhaustion, our tendency to scroll past the policy debate and doom-post about the inevitable robot apocalypse. Doomerism is a form of political paralysis. If you believe the future is already determined, you don’t organize, you don’t vote, you don’t fight. You wait for the catastrophe and feel validated when it arrives.
JA Westenberg: A Soft-Landing Manual for the Second Gilded Age
Writing effective test cases is as important as writing the business logic in your application. This blog post dives into the simple yet effective ways developers can use when crafting test cases.
Lack of assertions in the test cases
We all have written controller test cases in the past. It could be rspecs, minitests, or any other framework. Consider we have an UsersController and the code look like this:
# app/controllers/users_controller.rb
class UsersController < ApplicationController
def create
@user = User.new(user_params)
if @user.save
# Sending welcome email
UserMailer.welcome_email(@user).deliver_later
# Creating default settings for user
Use…
Authors: Irina Nazarova, CEO, and Travis Turner, Tech Editor
Topics: Performance, Real-time, Open Source, Performance & scale, Frontend & real-time, Node.js, WebSocket

Evil Martians benchmarked five WebSocket servers for Node.js: Socket.io, uWebSockets.js, and AnyCable (OSS and Pro). How we caught our own load generator lying, and how to make WebSocket benchmark numbers honest.
I compared five ways to run WebSockets on Node.js: default Socket.io, Socket.io with Connection State Recovery, uWebSockets.js, AnyCable OSS, and AnyCable Pro. In this post, I share how a banned laptop, a lying load generator, and a stubborn throughput disparity taught me that the hardest part of benchmarking is getting…
## Summary
The protected copy helper behind Node#dup and #clone unwrapped its
source argument as an xmlNode without a type check.
Supplying a non-Node (e.g. a Namespace) made it read an xmlNs
out of bounds, crashing the process.
Nokogiri 1.19.4 performs a type check and raises TypeError when an
argument of invalid type is passed.
Only CRuby is affected. JRuby is not affected.
## Severity
The Nokogiri maintainers have evaluated this as low severity.
This is only triggered by a programming error. It requires application
code to call the protected internal initialize_copy_with_args method
with an argument that is not a Nokogiri::XML::Node.
Nokogiri 1.19.4 now raises TypeError instead of…
Blue Ridge Ruby made a comeback in 2026 and Jeremy Smith joins the podcast to talk about how it went
Show Notes
Sponsors
Lots of teams out there are still overpaying for their hosting and getting tripped up by traffic spikes. If you’re on one of those teams, you need a better autoscaler. Judoscale uses better metrics, gives you more control, and reacts faster than any other autoscaler. Learn more at https://judoscale.com/
I started founding my second company in Germany in late January. It is now late June.
In that time, the state, two courts, a notary, a law firm, a tax firm, and software vendors have all found a way to bill me. Every single one of them, on time.
I have spent more than 9,600 euros to start a company: a little over 7,600 in fees and bills, plus 2,000 in share capital frozen in an account I am not allowed to touch. And after five months, here is what I have to show for it:
I have not been able to send a single invoice of my own.
Not one.
The work is happening. The clients are real. The one thing the state exists to let me do, bill them cleanly, is the one thing I still can’t.
The timeline
…
Some time ago, we migrated our work application from Rails 6 to Rails 8 in one big jump and adopted several new features that came with this version. One of those was a Procfile that defined the necessary processes to run the application in local environments, which is executed when you run bin/dev. If you look at the code of this file, you will find the real responsible party for executing all these processes: foreman (unless you modified the original file).
The first problem we started encountering was that all process outputs were mixed into a single stream, making it take us a long time to realize that, for example, JavaScript compilation had failed, which is why we weren’t seeing the…
How Ruby Itself Uses Dependabot: A Look Behind MRI's Dependency Management June 23, 2026 When people think about Dependabot, they usually picture a Rails application keeping its gems up to date. But Ruby itself—the MRI interpreter—also relies on Dependabot to automate dependency updates. Its configuration offers an interesting glimpse into how the Ruby core team … Continue reading How Ruby Itself Uses Dependabot: A Look Behind MRI’s Dependency Management →
This week I made a refactor to remove a job (ActiveJob::Base) that was used only in recurring.yml, and call a class method directly instead.
Sometimes it is ok to have a job, but sometimes using the method can help you write a little less code. And these days it is just a prompt away.
The example
I was working on a follow-up flow for users who had not updated their profile in over a year. The recurring task only needed to fan out work: find eligible users and enqueue one job per user.
Instead of scheduling a job in recurring.yml, like this…
follow_up_main_info_review:
class: "User::ScheduleMainInfoReviewFollowUpsJob"
schedule: "every day at 09:00"
With a thin wrapper job like this…
…
RubyGems 4.0.15 includes enhancements and bug fixes and Bundler 4.0.15 includes enhancements and bug fixes.
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.15
RubyGems Release Notes
Enhancements:
- Rubygems: Fix Gem::Request for PQC support, adding integration connection tests. Pull request #9615 by junaruga
- Reduce peak memory usage of full index loading and bundle install. Pull request #9618 by hsbt
- Installs bundler 4.0.15 as a default gem.
Bug fixes:
- Forward security policy to old-format gems. Pull request #9611 by hsbt
Bundler Release Notes
…
Getting acquired is exciting, but the technical story of your acquisition gets told after the deal closes.
Continue Reading
We have been spending time teaching Claude Code how to help us upgrade Rails applications. Along the way we learned that the most reusable piece of that effort is not the prompt we type, it is the skill we wrote once and now load on demand.
If you keep pasting the same checklist or procedure into a chat, a skill is probably what you want. This post walks through writing your first skill from scratch and keeping it lean, so it triggers when you want and costs almost nothing when you don’t.
What Is a Skill?
A skill is a folder with a SKILL.md file inside it. The file has two parts: YAML front matter that tells Claude when to use the skill, and Markdown instructions that tell Claude what…
Somewhere in the mid-aughts eXtreme Programming (XP) practices became widely-discussed in software. From that time forward, a strange chasm emerged in the discourse.
I would stumble across large pockets of programmers discussing—with full confidence—the fact that “nobody is actually doing TDD”, “pairing all the time is a myth”, “no one can actually succeed with those practices, it’s just hype”. Meanwhile, I was writing all my code test-first, spending nearly all of my time pair-programming, and by all accounts succeeding greatly. Not to mention enjoying coding more than ever.
It was like living in parallel universes. In my universe, XP practices were a welcome way of life, making…
This is a short post to show the compatibility between JRuby and
Ruby on Rails across different versions. JRuby is an implementation
of Ruby that runs on the JVM, so picking a version means lining up four things at once:
- JRuby release
- Ruby version
- Minimum Java version
- Rails version
JRuby tracks a specific CRuby (MRI) language level per release, and Rails support on JRuby is delivered
through the activerecord-jdbc-adapter gem,
whose version number mirrors the Rails version it targets. The Rails versions listed below are the
ones that both run on that JRuby line’s Ruby language level and have a matching adapter release.
JRuby Version
Ruby Compatibility
…
Aji and Joël join forces to discuss graph and tree structures, and their connection to the emergent properties, attributes and qualities you can find from a largely connected group of data.
Joël dives into their recent graphs and tree work through a contracting system, whilst Aji looks back at when he previously tried to serialise a graph or tree to a database.
—
Watch Joël’s Blue Ridge Ruby talk here, or Matheus’ Ruby Internal talk from last year here.
There’s still time to secure your place at thoughtbot’s upcoming UK meet ups over the next month.
London Tech Leader Meetup - Tuesday June 23rd
Brighton Tech Leader Meetup - Wednesday June 24th
Brighton Ruby - Thursday June 25th…
Your hosts for this episode have…
### Summary
`Concurrent::AtomicReference#update` can enter a permanent busy retry
loop when the current value is `Float::NAN`.
The issue is caused by the interaction between:
- `AtomicReference#update`, which retries until `compare_and_set(old_value,
new_value)` succeeds.
- Numeric `compare_and_set`, which checks `old == old_value` before
attempting the underlying atomic swap.
- Ruby NaN semantics, where `Float::NAN == Float::NAN` is always `false`.
As a result, once an `AtomicReference` contains `Float::NAN`, calling
`#update` repeatedly evaluates the caller's block and never returns.
In services that store externally derived numeric values in an
`AtomicReference`, this can cause…
### Summary
`Concurrent::ReentrantReadWriteLock` can incorrectly grant a write lock
after one thread acquires the read lock 32,768 times.
The lock stores a thread's local read and write hold counts in one
integer. The low 15 bits are used for the read hold count, and bit 15
is used as `WRITE_LOCK_HELD`. After 32,768 reentrant read acquisitions,
the local read count crosses into the write-lock bit. `try_write_lock`
then treats the thread as already holding a write lock and returns
`true` without setting the global `RUNNING_WRITER` bit.
This breaks the core mutual-exclusion guarantee: the caller is told
it has a write lock, but other threads can still hold or acquire
read locks at the same…
### Summary
`Concurrent::ReadWriteLock#release_write_lock` does not verify that the
calling thread acquired the write lock. Any thread with access to the
lock object can release an active write lock held by another thread. A
second writer can then enter its critical section while the first writer
is still running.
`Concurrent::ReadWriteLock#release_read_lock` also decrements the shared
counter even when no read lock is held. Calling it on a fresh lock
changes the counter from `0` to `-1`, after which normal read acquisition
raises `Concurrent::ResourceLimitError`.
This is a synchronization correctness issue in the public
`Concurrent::ReadWriteLock` API. It should not be framed as…
## Impact
If this library is used to implement a WebSocket server on top of a
TCP server, by using the WebSocket::Driver.server() method, then a
client can cause the server to crash by sending a Host header that
is not a valid host[:port] string. When this happens, a URI::InvalidURIError
exception is raised which is not caught, and this can cause the server
process to crash if the application does not catch the error from
the parse() method itself.
## Acknowledgements
This issue was discovered and reported by Pranjali Thakur,
DepthFirst Security Research Team.
### Summary
`Oj.load` in `:object` mode reads uninitialized stack memory (and,
for long keys, reads out of bounds) when parsing a JSON object whose
key is 254 bytes or longer. The interned bytes can surface to the
caller, disclosing process stack memory.
### Impact
Information disclosure of process stack memory to a caller that parses
untrusted JSON with `Oj.load(..., mode: :object)`. For keys >= 256
bytes it is also an out-of-bounds read (CWE-125).
Severity is bounded by several preconditions: it requires `:object`
mode (which is already discouraged for untrusted input), the leaked
bytes are uncontrolled (the attacker cannot choose what is disclosed),
and the data only reaches an…
### Summary
`Oj.dump` is vulnerable to a stack-based buffer overflow when a large
`:indent` value is provided by the developer. `fill_indent` in `dump.h`
calls `memset(indent_str, ' ', (size_t)opts->indent)` without validating
the size. When `opts->indent` is set to `INT_MAX` (2,147,483,647), the
`(size_t)` cast preserves the large value and `memset` writes 2 GB into
the stack-allocated `out` buffer (4,184 bytes), corrupting the stack
and crashing the process.
### Summary
`Oj::Doc#each_child`, when invoked recursively over a deeply nested JSON
document, overflows a fixed-size stack buffer and aborts the process. This is a
denial of service reachable from untrusted JSON.
### Impact
Reliable denial of service: any endpoint that calls
`Oj::Doc.open(untrusted) { |d| d.each_child ... }` recursively can be
crashed with a small deeply-nested payload. On builds with a stack
protector (the default, `-fstack-protector-strong`) the canary aborts
the process before the saved return address is used. The Step-1 heap
OOB writes into `struct _doc` fields do occur, but are masked in
practice because the Step-2 stack overflow crashes first; turning them
into…
Every seven weeks or so, each Aha! engineer takes a week of support rotation. I caught myself doing something dumb during my last one. A ticket came in. I clicked over to our production log viewer, narrowed the time range, and started piecing togeth
Certain shifts in software history feel like freedom because they remove familiar signals of control. In reality, they relocate rigor closer to where truth lives. They make it harder to fake progress.
leaflet.pub: Relocating Rigor
The fourth edition of Rails World is fast approaching with just over three months to go, so it’s time to meet the speakers who will join us this year in Austin, TX.
But first: Thank you to everyone who applied this year. When we opened the CFP, three of the nine topics were AI-related, but in the end half of all submissions were in these three categories. Not at all surprising considering the year we are having, but there are only 20 speaking slots, and still a lot happening in Rails outside of (or maybe adjacent to) AI, so finding the right balance took a little more work this year. (Big shout out to the content committee for their patience, discernment, and endless review cycles!)
With…
# Uncontrolled Recursion in NestedParamsEncoder Allows Stack
Exhaustion DoS via Deeply Nested Query Parameters
## Summary
`Faraday::NestedParamsEncoder`, the default nested query parameter
encoder/decoder in Faraday, decodes nested query strings without
enforcing a maximum nesting depth.
A crafted query string such as:
```text
a[x][x][x][x]...[x]=1
```
causes Faraday to build a deeply nested Ruby `Hash` structure. The
internal `dehash` routine then recursively walks this attacker-controlled
structure without a depth limit. At sufficient depth, Ruby raises an
uncaught `SystemStackError` (`stack level too deep`), crashing the
calling thread or worker.
This can lead to denial of…
# Unauthenticated nested page API leaks restricted & unpublished content
- **Location:** `app/controllers/alchemy/api/pages_controller.rb:28`
(`Api::PagesController#nested`)
- **Affected version:** Alchemy CMS 8.3.0.dev (Rails 8.1.3)
## Description
The unauthenticated `GET /api/pages/nested` endpoint returns the full
page tree to any anonymous caller, including restricted (member-only)
pages and unpublished/draft pages that should be hidden.
Appending `?elements=true` additionally dumps the element/ingredient
**content** of restricted pages, fully bypassing the access control
the sibling `show` and `index` actions enforce.
## Root cause
`Api::PagesController#nested` calls no…