RubyGems 4.0.12 includes enhancements and bug fixes and Bundler 4.0.12 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.12
RubyGems Release Notes
Enhancements:
- Remove cygwin from WIN_PATTERNS. Pull request #9527 by fd00
- Installs bundler 4.0.12 as a default gem.
Bug fixes:
- Fall back to lockfile version when
BUNDLE_VERSION is “lockfile”. Pull request #9545 by hsbt
- Read
BUNDLE_VERSION env var in BundlerVersionFinder. Pull request #9538 by hsbt
Bundler Release Notes
Enhancements:
For more than two decades, Ruby has shaped how we think about software development at thoughtbot. It influenced how we write code, how we collaborate, how we teach, and how we build products alongside our clients. Many of the practices, tools, and ideas that define our company today were either born from or heavily influenced by the Ruby community.
Ruby also helped shape our careers, friendships, businesses, and opportunities. That’s a big part of why we’re excited to share that thoughtbot is joining the Ruby Alliance alongside Gusto as a founding company.
What is the Ruby Alliance?
The Ruby Alliance is a new coalition of companies making a long-term financial and operational…
A use-after-free vulnerability has been discovered in the pthread-based getaddrinfo timeout handler of Ruby. This vulnerability has been assigned the CVE identifier CVE-2026-46727. This issue has been fixed in Ruby 4.0.5. We recommend upgrading Ruby.
Details
A race condition exists in the timeout cancellation path of rb_getaddrinfo used by Addrinfo.getaddrinfo(..., timeout:) and Socket.tcp(..., resolv_timeout:). A remote attacker who can delay DNS responses near the specified timeout may cause the Ruby process to dereference freed memory and crash.
Recommended action
Please update to Ruby 4.0.5 or later.
Workaround
If you cannot upgrade immediately, avoid passing timeout: to Addrinfo.…
Ruby 4.0.5 has been released.
This release only contains a security fix for
CVE-2026-46727: Use-after-free in pthread-based getaddrinfo timeout handler
and a build system regression in Ruby 4.0.4 under C locale [Bug #22065].
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.6 will be released in July, 4.0.7 in September, and 4.0.8 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 gathered again at Working & Co in Buenos Aires for another Ruby Argentina meetup. As always, the event was streamed live on RubySur’s YouTube channel, and our sponsors (SINAPTIA, Rootstrap, OmbuLabs, and Crunchloop) kept us fed and hydrated throughout the night.
Vacas, Rails y Blockchain
Ignacio Cesarani presented his thesis project: a cattle trading platform built with Ruby on Rails and blockchain. The interesting part is the architecture: it uses Ethereum RSK as a sidechain to record transactions immutably, while keeping operational data in a traditional database.
Break
After the first talk, we had time to eat, drink, and chat. The sponsors put together a good spread, and the…
Authors: Ivan Chepurin, Frontend Engineer, and Travis Turner, Tech Editor
Topics: AI, Developer Community

AI-assisted code generation is not free. It comes with a hidden cost: burnout. Are we dangerously ignorant to this problem? And how can we cope with it? In this post, we discuss this question.
We’re more productive than ever. AI allows us to generate code at supersonic speeds, unfold entire modules in seconds, and ship thousands of lines of code. It's easier to pick up tasks and generate value, even in unfamiliar codebases. But there’s a dark side. AI-assisted code generation isn't free; there's a hidden cost that we as an industry are only beginning to realize: AI burnout. Are we…
We’re excited to share that thoughtbot has become the second company to join the Ruby Alliance.
For 23 years, thoughtbot has helped shape the Ruby ecosystem through thoughtful engineering practices, trusted guidance on large-scale application development, and some of the most respected educational resources in the community.
Their participation in the Ruby Alliance brings experienced leadership, operational perspective, and a strong commitment to helping support the long-term health of Ruby and the infrastructure the community depends on.
As the Ruby Alliance continues to take shape, thoughtbot’s consulting experience and community perspective will help inform how Alliance companies can work…

Version 6.1.3 of the Passenger application server has been released. This release adds packages for Ubuntu 26.04 "resolute", and removes packages for Ubuntu 25.10 "questing" and Ubuntu 20.04 "focal".
Added support for Ruby app post response hooks
The optional feature of Rack 3 (`rack.response_finished`) is now supported, Closes GH-2418.
Fix a crash when buffer creation fails
Passenger could crash when it was unable to create a buffer file while handling a request that exceeded the in-memory buffer size. This was fixed through additional pointer validation.
Updates & improvements
- [Nginx] Build Nginx dynamic modules against nginx-dev sources on Ubuntu/Debian where available to accommodate Ubuntu's…
Rails 8 introduces a significant change to the asset pipeline by making
Propshaft
the default asset pipeline,
replacing
Sprockets
which has been the default since Rails 3.1.
This
change
reflects the modern approach to asset management in Rails applications.
What is Propshaft?
Propshaft is a lightweight asset pipeline that does one thing well:
it fingerprints assets and serves them.
Unlike Sprockets which bundles, transpiles, and concatenates files,
Propshaft delegates those responsibilities to specialized tools.
Here’s what each pipeline actually does:
Feature
Sprockets
Propshaft
Asset fingerprinting
Yes
Yes
…
AI-generated code can quietly introduce maintainability risks into long-lived Ruby on Rails applications. Here are four patterns engineering leaders should pay attention to.
Continue Reading
Authors: Nina Torgunakova, Frontend Engineer, and Travis Turner, Tech Editor
Topics: Developer Products, Next.js, CSS, JavaScript, TypeScript

Arabic, Hebrew, and other right-to-left script users often can't type properly in apps that never considered them. The fix is usually two HTML attributes. Here's exactly what to add, and when.
You shipped, the app works, users sign up. Then a bug: "The input field doesn't work properly." Turns out their language is Arabic. When typing a prompt, text renders left-to-right. This meant alignment was off, punctuation lands on the wrong side, and the whole sentence reads garbled. When a user can use a right-to-left language, even English apps will break. This…
Business Goblin (left) is a character created by friend and colleague Matthew
Grey (right). Originally drawn for an internal presentation, he represents
greedy unscrupulous businesses selling fake AI hype without the ability to
follow through on their promises. After the presentation, Business Goblin took
on a bit of a life of his own, appearing around the office as a life-sized
coreflute cutout.
Recently, after a couple of Friday evening beers, a small group of collegues and
I asked the question: what if you could email Business Goblin and he actually
emailed you back? I happened to be looking for an LLM-related side project, and
so 24 hours later https://goblin.business/ was up…
Send him an email…
I’ve never used “social” media. Instead, I read a lot on various topics: Rails, web/tech and beyond. Next to the weekly practical article a week on Rails, Hotwire, CSS, SaaS and design I published, I have, since March, started sharing some thoughts and notes. They’re not publicly listed, but accessible via Atom feed only.
I hope to see more platform-independent Twitter-style feeds from others too. Web standards like RSS/Atom are great and don’t lock you into a platform or company. Just linear posts, no ragebaits or shitposting from others (and if so, unsubscribe).
With Perron’s customisable feeds feature, this is super easy to set up. I also created a tiny Raycast extension that makes…
I…
May 18, 2026 Most Ruby developers use ranges every day: (1..5) ('a'..'z') (1...) (..10) They feel lightweight, expressive, and almost deceptively simple. 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 … Continue reading Inside Ruby’s Range: A Tour Through range.c →
From Ruby User to Ruby Committer: Lessons from Stan Lo's Open Source Journey May 17, 2026 Stan Lo didn't follow the conventional path. No CS degree, no bootcamp pedigree, no Silicon Valley zip code just steady, deliberate contributions to the Ruby ecosystem over nearly a decade. The result? Ruby committer status, the 2025 Ruby Prize, … Continue reading From Ruby User to Ruby Committer: Lessons from Stan Lo’s Open Source Journey →
A Rails test fixture accessor that returns an empty Array instead of a record, flaky between local and CI. The cause is method_missing-based fixtures colliding with a method turbo-rails mixes in. Here is the diagnosis and four fixes.
The Rails Infrastructure team built an open-source toolkit for benchmarking Bundler performance reliably across machines. Along the way I learned that AI is great for scaffolding, but you can’t oursource the engineering rigor required to catch when numbers don’t add up.
Read more on the Shopify’s Rails at Scale Blog
Hi, it’s Greg. Let’s explore this week’s changes in the Rails codebase.
Rails World 2026 update
General Admission tickets are now out, and the CFP is closing this weekend.
Book your ticket or apply to speak at: https://rubyonrails.org/world/2026.
A new add-on tutorial is ready for community review
This builds on the existing e-commerce app and adds a complete Product Reviews
system with ratings, image uploads, rating filtering, and admin management. If
you want to help by reviewing, leave your feedback in the PR here:
https://github.com/rails/rails/pull/57244
Also, there are 2 new guides ready for community review:
https://github.com/rails/rails/pull/57371
and
https://github.com/rails/rai…
Add default #render_in implementation to ActiveModel::Conversion
This pull request adds a default #render_in…
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 →
## Summary
When the `Timeoutable` module is enabled in Devise, the
`FailureApp#redirect_url` method returns `request.referrer` — the
HTTP `Referer` header, which is attacker-controllable — without
validation for any non-GET request that results in a session timeout.
An attacker who hosts a page with an auto-submitting cross-origin
form can cause a victim with an expired Devise session to be
redirected to an arbitrary external URL. This contrasts with the
GET timeout path (which uses server-side `attempted_path`) and
Devise's own `store_location_for` mechanism (which strips external
hosts via `extract_path_from_location`), both of which are protected;
only the non-GET timeout redirect path…
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:…
Sidekiq-cron thru 2.3.1, an open-source scheduling add-on for Sidekiq,
is vulnerable to a cross-site scripting (xss) vulnerability via
crafted URL being rended from cron.erb.
### Impact
Admin session cookies were not invalidated when an admin user logged
out. An attacker with access to a valid admin session cookie could
continue to access admin functionality after logout, until the
cookie expired or session secrets were rotated.
This affects applications using Koi admin authentication where an
admin session cookie may have been exposed, cached, intercepted, or
otherwise retained after logout.
### Patches
The issue has been patched by recording admin logout time and
rejecting any admin session cookie created before the user’s
most recent logout.
Users should upgrade to the patched Koi releases once available.
### Workarounds
Katalyst Koi recommends…
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…