SQL: Fast threshold counts with LIMIT
Performing COUNT(*) on large tables is slow. Sometimes you don’t need the exact number once results exceed a certain threshold.
For example, you may only need to display 100+ in the UI. Using a plain COUNT(*) would scan all matching rows.
The following query would be pretty slow when counting many rows because it has to scan all rows.
SELECT COUNT(*) FROM movies;
Limiting within a subquery
Use a subquery with LIMIT
to cap the scan early. You’ll get the exact number up to 100 otherwise you can show 100+.
SE...
How to tweak RSpec's truncation behavior
When RSpec sets out to print any given object to the console, it will never print more than 200 characters from it. Only the first and last 100 chars from overly long strings are displayed, which sometimes means that the root cause for the failing test is buried in truncation.
For example, I could not easily make out the reason for this failure:
Failure/Error: expect { crawler.pull_new_commits }.not_to raise_error
expected no Exception...
zizmor - Static analysis for GitHub Actions
The linked tool can be used to scan your CI/CD workflows for potential security issues and suboptimal defaults if they are based on GitHub Actions.
For example, it warns you about
- string interpolations that may expand into attacker-controllable code
- suboptimal defaults like e.g.
persist-credentials: true
for the checkout action - actions that are not pinned to a tag instead of a git SHA
Some of the warnings can be auto-fixed. The tool comes wi...
Unpoly 3.12.0 released
This release adds asynchronous compilers and many other features requested by the community.
We also fixed a number of performance regressions introduced by Unpoly 3.11.
Breaking changes are marked with a ⚠️ emoji and polyfilled by unpoly-migrate.js
.
Asynchronous compilers
Compiler functions can now be [async
](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
Geordi 12.6.0 was released
Changelog
-
geordi dump
: Allow to forward the compression option to the underlyingdumple
command, e.g.geordi dump --compress=zstd:3
(for PostgreSQL) orgeordi dump --compress
(for MySQL). -
dumple
: Allow to specify a compression algorithm for PostgreSQL, e.g.dumple --compress=zstd:3
. The already supported compression for MySQLdumple --compress
is kept untouched.
In PostgreSQL you will notice a speedup of ~50%.
Example
Performance improvements during a deploy (e.g. lib/capistrano/tasks/db.rake
)
namespace...
Format your JavaScript with prettier
prettier calls itself an opinionated code formatter. I recommend using it for your JavaScript and TypeScript code.
prettier only concerns itself with the formatting of your JavaScript (and also some other file types like json or yaml). When you use it, it has an opinion on every single whitespace and linebreak, as well as a few other things. You renamed a variable and now your line is a bit longer than looks good? prettier will reformat your code.
This might not work for you if you have strong opinions yourself....
Automatic Log Rotation in Rails
Rails log files rotate automatically when they reach approx. 100MB:
$ ls -lh log/
-rw-r--r-- 1 user group 55M Sep 15 09:54 development.log
-rw-r--r-- 1 user group 101M Aug 22 13:45 development.log.0
This behavior is a built-in feature of Ruby's standard Logger
class, which Rails uses by default.
To control the maximum file size, set config.log_file_size in yo...
Stabilize integrations tests with flakyness introduced by Turbo / Stimulus / Hotwire
If you run a Rails app that is using Turbo, you might observe that your integration tests are unstable depending on the load of your machine. We have a card "Fixing flaky E2E tests" that explains various reasons for that in detail.
Turbo currently ships with three modules:
- Turbo Drive accelerates links and form submissions by negating the need for full page reloads.
- Turbo Frames decompose pages into independent contexts, which scope navigation and can be lazily loaded.
- T...
Rails: Redirecting the Logger output temporary aka showing Rails logs in the console
Most of the time, when you are interested in any log output,
- you see the logs directly on your console
- or you tail / grep some logfile in a separate terminal window
In rare cases it's helpful to redirect the Logger output temporary to e.g. STDOUT
.
Rails.logger = Logger.new(STDOUT)
ActiveRecord::Base.logger = Logger.new(STDOUT)
User.save!
#=> D, [2025-09-08T11:12:26.683106 #1094157] DEBUG -- : User Load (1.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT $1 [["LIMIT", 1]]
Many frameworks in Rails ...
Disable SimpleCov if you only run a fraction of your tests
Coverage reports are rarely useful if you run only small parts of your test suite.
Just do not load SimpleCov in this case, and you will see less noise in your test output:
if RSpec.configuration.files_to_run.count > 5
require "simplecov"
SimpleCov.start 'rails'
end
See also
Javascript: How to match text by Unicode properties
The linked MDN article is quite informative of a neat feature supported by all major browsers: Unicode character class escape.
You can use it to write regular expressions that work on the full UTF-8 space, not just Latin/ASCII. For example, a password policy matcher might include regular expressions like [A-z]
or [0-9]
, but those do not match e.g. German umlauts or [Eastern Arabic Numerals](https:/...
RSpec: Marking sections in long examples
RSpec examples can get quite long, especially in feature specs. This makes them hard to read & understand. Also, when executing them, it may take seconds to see any progress.
To improve this, I have successfully been using a little "step" helper in my tests. It marks semantic sections, structuring an example while improving documentation. When the test runs, each step prints its message (or a dot, depending on your formatter).
# spec/support/step_helper.rb
module StepHelper
# Use this helper to label groups of related actions in l...
How to silence Puma for your feature tests
When RSpecs runs the first feature spec, you may see log output like this:
Capybara starting Puma...
* Version 6.5.0, codename: Sky's Version
* Min threads: 0, max threads: 4
* Listening on http://127.0.0.1:39949
You can disable this behavior by tweaking Capybara's Puma server in your spec/support/capybara.rb
:
Capybara.server = :puma, { Silent: true }
Note
You don't need to configure this if you're using system tests with modern versions of Rails. They do [exactly the same](https://github.com/rails/rails/blob/ma...
How to define a table name prefix for all Rails models in a given namespace
ActiveRecord computes table names of model classes, and results are usually just like you'd expect.
Adding a prefix for all classes in a namespace can feel a odd or broken, but does not have to be. It's actually very easy when done right.
Summary (tl;dr)
Here's the short version: Define a table_name_prefix
method in the namespace module, and do not define any table_name_prefix
in ActiveRecord classes inside of it. If this sounds familiar, we have [a card about using it already](https://makandracards.com/makandra/47198-rails-namespac...
Updated: How to allow testing beforeunload confirmation dialogs with modern ChromeDrivers
ChromeDriver 135 started following the W3C spec more closely, which broke testing beforeunload confirmations again. To get working confirmations in a testing browser again, unhandled_prompt_behavior
needs to be set to the hash { default: :ignore }
.
Selenium doesn't currently support setting this option to a hash, so a monkey patch is needed.
Updated: Testing Accessibility using Orca
As it's quite hard to use a screen reader when you have never done so before, I added a guide on how to visually review the spoken text instead.
Debugging Orca's Output
We can visually review everything the screen reader says by hacking together a real-time transcript of Orca's speech.
To do so, run orca in a CLI window telling it to write a temporary debug log (without Braille to reduce noise)
orca --disable braille --debug-file=/tmp/orca-log.txt
Tip: The screen reader will still be audible. You can reduce its volume ...
Managing chrome versions for selenium
Currently we often use geordi to run cucumber
and rspec
tests. Geordi takes care of installing a matching chromedriver
for the installed google-chrome
binary. The google-chrome
binary is managed by apt
.
Another approach is to use the Selenium Manager for installing and using the correct browser versions for you. Here is the setup you need for your integration tests:
Capybara.register_driver :chrome do |app|
options = Sele...
Rails: Handling actions that need to happen after all transactions
In Rails 7.2. the feature ActiveRecord.after_all_transactions_commit
was added, for code that may run either inside or outside a transaction (we have a special card for nested transactions in general) and needs to perform work after the state changes have been properly persisted. e.g. sending an email.
Example
def publish_article(article)
article.update(published: true)
ActiveRecord.after_all_transactions_commit do
PublishNotification...
Rails: Testing exceptions with the rescue_responses setting
In Rails 7.2 the new default for config.action_dispatch.show_exceptions
is rescuable
.
-
:rescuable
: It will show a Rails error page in the response only for rescuable exceptions as
defined byActionDispatch::ExceptionWrapper.rescue_responses
. In the
event of an unexpected internal server error, the exception that caused
the error will still be raised within the test so as to provide a useful
stack trace and a good debugging experience. -
:all
: It wi...
Testing for Performance: How to Ensure Your Web Vitals Stay Green
Frontend performance and user experience are orthogonal to feature development. If care is not taken, adding features usually degrades frontend performance over time.
Many years, frontend user experience has been hard to quantify. However, Google has developed some metrics to capture user experience on the web: the Web Vitals. The Core Web Vitals are about "perceived loading speed" (Largest Contentful Paint), reactivity (Interaction to Next Paint) and visual stability (Content Layout Shift).
I have recent...
You don't always need a custom matcher to write clean RSpec tests
When you repeat complex assertions in your tests multiple times, it might be a good idea to extract a custom RSpec matcher. This not only tidies up your own code, but also makes it easier to write future specs.
However, not all situations are well-suited for that. Sometimes the effort isn't worth it, e.g. when your matcher would need too many parameters to be reusable. In those cases, you can also simply extract a private method:
describe `/search` do
it "doesn't lose the infinite scroll's filter state when navig...
Adding comments to ambiguous database columns
The DB schema is the most important source of truth for your application and should be very self-explanatory. If determining the true meaning of a DB column requires historical research in your issue tracker or reverse engineering of your source code you might consider adding a comment.
Both PostgreSQL and MySQL support comments in the DB schema:
- For new columns: https://guides.rubyonrails.org/active_record_migrations.html#comments
- Changing the comment for existin...
Selenium: Fix Chrome's "Unsafe Password" Warning
tl;dr
Set
profile.password_manager_leak_detection
tofalse
in your Selenium Chrome options to disable password leak detection and suppress the warning.
Problem
When running Selenium tests with recent versions of Chrome and Chromedriver (e.g., version 136+), entering “unsafe” (weak or reused) passwords in forms triggers a browser warning:
"This password has appeared in a data breach…"
This alert can break automated test runs, especially in CI/CD pipelines.
Solution
You can **disable Chrome’s password leak ...
Using FactoryBot in Development
If you need dummy data to play around with in development, it's often faster to reuse your existing factories instead of using the UI or creating records in the Rails console. This approach saves time and gives you useful defaults and associations right out of the box.
You can use FactoryBot directly in the Rails console like this:
require 'factory_bot_rails' # Not needed if the factory_bot_rails gem is in the :development group
FactoryBot.create(:user)
You can also apply traits or override attributes:
FactoryBot.create...