Ollama: Log generation runtime
When an LLM is part of a request, you want to keep track of how much of the runtime was spent waiting on it, how many calls it took, and the ratio of input to output tokens without opening a debugger every time. Passively watching these numbers catches prompt bloat, runaway tool-call loops, and regressions from model changes just by scrolling the log. The same pattern applies to any slow external API you want visibility on.
Hooking into Rails' controller instrumentation allows us to get additional information like this in every log line:
...
Ollama: Strip image data from VCR recorded requests
When testing Ollama vision requests with VCR, the recorded cassettes will contain the full base64-encoded image payloads. A single image can easily be hundreds of kilobytes; a handful of recorded interactions will balloon your repository size significantly.
The VCR configuration below solves two problems:
- It scrubs base64 image data from cassettes before they are written to disk, replacing each image with a placeholder string
- It filters Basic Auth credentials so they are never committed
It also registers a custom request matcher so ...
Ollama: How to generate reproducible results
By default, Ollama produces non-deterministic output: The same prompt will yield slightly different results each time. To get reproducible outputs, you must set both temperature: 0 and a fixed seed in the request options.
curl http://localhost:11434/api/chat -d '{
"model": "qwen3.5:35b",
"messages": [
{
"role": "user",
"content": "Extract the invoice total from this document",
"images": ["iVBORw0KGg..."]
},
],
"options": {
"seed": 101,
"temperature": 0
}
}'
That said, you might not ...
Updated: How to get notified when Claude Code needs your input
I've updated my "claude wants user input" script. It's now a bit more complicated, but it will now open the configured editor/IDE on the path where claude is running when you click on the notification so you don't have to search the agent's window.
Rails: Report CSP Violations to a log file
You can report CSP violations to a log file. Note that there will be a lots of noise, that is not related to errors in your application but raised from various browser extensions of your visitors.
Add the endpoint in you CSP config/initializers/content_security_policy.rb:
Rails.application.configure do
config.content_security_policy do |policy|
# Settings for the policy
policy.report_uri '/content_security_policy_report'
end
end
Create a controller app/controllers/content_security_policy_reports_controller.rb ...
CSP: Nonces are propagated to imports
When you load a <script> with a nonce, that script can await import() additional sources from any hostname. The nonce is propagated automatically for the one purpose of importing more scripts.
This is not related to strict-dynamic, which propagates nonces for any propose not limited to imports (e.g. inserting <script> elements).
Example
We have a restrictive CSP that only allows nonces:
Content-Security-Policy: default-src 'none'; script-src 'nonce-secret123'
Our HTML loads script.js using that nonce:
A restrictive (but still practicable) CSP for Rails projects
Below is a strict, but still workable Content Security Policy for your Ruby on Rails project. Use this CSP if you want to be very explicit about what scripts you allow, while keeping pragmatic defaults for styles, images, etc. This CSP does not use the viral strict-dynamic source (reasoning).
We also have a very compatible CSP which is more liberal. Compatibility might outweigh strictness if you have a lot of scripts you can...
Caching file properties with ActiveStorage Analyzers
When working with file uploads, we sometimes need to process intrinsic properties like the page count or page dimensions of PDF files. Retrieving those properties requires us to download (from S3 or GlusterFS) and parse the file, which is slow and resource-intensive.
Active Storage provides the metadata column on ActiveStorage::Blob to cache these values. You can either populate this column with ad-hoc metadata caching or with custom Analyzers.
Attachment...
Sending newsletters via rapidmail with SMTP and one-click unsubscribe
If you need to implement newsletter sending, rapidmail is a solid option.
Support is very fast, friendly and helpful, and the initial setup is simple. Since rapidmail works via SMTP, you can simply ask the Ops team to configure SMTP credentials for your application.
You also do not need to use rapidmail’s built-in newsletter feature. Instead, you can send emails as transactional mails, which allows you to keep the entire newsletter logic inside your application.
One thing to keep an ey...
Opt out of selenium manager's telemetry
If you use the selenium-webdriver gem, it will sneakily phone home once every hour whenever you run a browser based feature spec.
Check if you're affected
Check if ~/.cache/selenium/se-metadata.json exists. (It contains a "ttl" timestamp of its last/next anaytics call. You can parse it with Ruby's Time.at.)
Opt out
You can opt out either globally:
# .bashrc
export SE_AVOID_STATS=true
or project based
# spec_helper...
Cucumber CI job quirks
Most of our CI pipelines don't use the --retry flag for Cucumber and instead build their own retry via the tmp/failing_features.txt file.
Benefits:
- It's possible to only use
-f prettyfor the rerun.
Drawbacks:
- MAJOR: With our current setup, when the main run fails without writing a
tmp/failing_features.txt(e.g. due to a syntax error), the CI job will pass - MINOR: With our current setup, we lose the test coverage of the main run
A fix for the passing CI despite syntax error could look like this:
cucumber:
# ...
sc...
Git: Finding changes in ALL commits
Finding changes
When you're looking for a specific change in Git, there are multiple axes you can choose:
-
git log -- path/to/filelists all commits that touch a file -
git log -G some_stringlists all commits where the diff contains "some_string"
Note that you can do most of these things with Git tools as well, e.g. tig path/to/file.
Considering ALL commits
By default, only the current branch (HEAD) is searched. To search across the entire local repository, add these options:
-
--all: Search all known refs (branches...
File System Access API: Recursive Directory Traversal
The File System Access API is a new capability of modern browsers that allows us to iterate over selected folders and files on a user's machine. Browser support is not great yet, but if the feature is only relevant for e.g. a single admin user it could still be worth using it prior to wider adaption instead of building yet another ZIP upload form.
Below is a simple compiler that i used to evaluate this feature.
!...
GoodJob: Ensure you get notified about background exceptions
GoodJob and ActiveJob rescue exceptions internally, preventing exception_notification from triggering. This can cause silent job failures.To get notified, subscribe to ActiveJob events and configure GoodJob's on_thread_error hook. This lets you manually call your exception notifier for every retry, discard, or internal GoodJob error.
# config/initializers/good_job.rb
# Manually notify on job failures, as they are handled internally by ActiveJob/GoodJob.
ActiveSupport::Noti...
Reliably sending a request when the user leaves the page
navigator.sendBeacon is a way to reliably send a POST request, even on unload.
Please note, however, that there are generally two ways to detect a "user leaving the page":
- The
unloadevent, which fires after a page is actually gone (e.g. after tab close, page refresh, and navigation away). - The
visibilitychangeevent. It is much softer, and will fire after tab contents have been hidden by any means (e.g. when closing a tab, but also when switchin...
Stabilize integrations tests with flakiness 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...
Processing GitLab Merge Requests within RubyMine
GitLab has a RubyMine plugin that enables you to review and process merge requests within RubyMine!
Setup
- Open RubyMine settings (Ctrl + Alt + S) > Plugins > Search for "GitLab" > Install
- (You might need to re-open settings afterwards.)
- In the RubyMine settings > Version Control > GitLab > Connect your GitLab account with "+"
Working with merge requests
- From the Actions menu (Ctrl + Shift + A), choose "View merge...
Better performance insights with gem `rails_performance`
Even if you don't make any beginner mistakes like N+1 queries or missing DB indices, some requests can have bad performance. Without good performance metrics, you probably won't notice this until it's too late.
We investigated multiple gems and found that rails_performance (https://github.com/igorkasyanchuk/rails_performance) provides a lot of valuable information with very little setup cost. It only needs Redis which we use in the majority of our applications anyw...
Web performance snippets: little scripts that return performance metrics
Use these snippets when you want to measure yourself.
Currently available:
Core Web Vitals
Largest Contentful Paint (LCP)
Largest Contentful Paint Sub-Parts (LCP)
Quick BPP (image entropy) check
Cumulative Layout Shift (CLS)
Loading
Time To First Byte
Scripts Loading
Resources hints
Find Above The Fold Lazy Loaded Images
Find non Lazy Loaded Images outside of the viewport
Find render-blocking resources
Image Info
Fonts Preloaded, Loaded, and Used Above The Fold
First And Third Party Script Info
First And Third Party Script Timings
I...
Sidekiq: How to check the maximum client Redis database size
You can check the maximum client Redis database size in Sidekiq with this command.
Sidekiq.redis { |redis| puts redis.info.fetch('maxmemory_human') }
#=> 512.00M
If you just want the maximum database size for a known Redis database URL you can use the Redis Ruby client or the Redis CLI:
Redis database size via Ruby client
irb(main):002> Redis.new(url: 'redis://localhost:16380/1').info.fetch('maxmemory_human')
=> "512.00M"
Redis database size via CLI
$ redis-c...
Rails: Keeping structure.sql stable between developers
Why Rails has multiple schema formats
When you run migrations, Rails will write your current database schema into db/schema.rb. This file allows to reset the database schema without running migrations, by running rails db:schema:load.
The schema.rb DSL can serialize most common schema properties like tables, columns or indexes. It cannot serialize more advanced database features, like views, procedures, triggers or custom ditionaries. In these cases you must switch to a SQL based schema format:
# in application.rb
config.a...
Implementing upload progress and remove button with ActiveStorage DirectUpload
DirectUpload allows you to upload files to your file storage without having to wait for the form to submit. It creates AJAX requests to persist the file within your form and wraps them in a little API. This card will show you how to use it in order to create in-place file uploads with progress and a remove button.
This is basic functionality, you may add additional elements, styles and logic to make this look fancy, but the core functionality is the same. I created a file upload that looks like this:

const svgo = require('svgo')
const options = {
// ...
loader: {
// ...
'.svg': 'copy', // this may be different...