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 pretty for 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/file lists all commits that touch a file
  • git log -G some_string lists 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":

  1. The unload event, which fires after a page is actually gone (e.g. after tab close, page refresh, and navigation away).
  2. The visibilitychange event. 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

  1. Open RubyMine settings (Ctrl + Alt + S) > Plugins > Search for "GitLab" > Install
    • (You might need to re-open settings afterwards.)
  2. In the RubyMine settings > Version Control > GitLab > Connect your GitLab account with "+"

Working with merge requests

  1. 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:

![Image](/makandra/625023/attachments/3...

Implementing authentication and authorization for ActiveStorage blobs/files

ActiveStorage does not provide any built-in way of implementing authentication for the available DirectUpload endpoint in Rails. When using DirectUpload as JS wrapper in the frontend, be aware that its Rails endpoint is public by default, effectively allowing anyone to upload an unlimited amount of files to your storage.

The DirectUploadController from @rails/activestorage bypasses your form controller because it uploads the file using an AJAX request that runs directly, before any form roundtrip happens. This is a comfortable solutio...

How to automatically optimize SVG files with esbuild

SVG files often contain redundant information, like editor metadata or hidden elements. When esbuild handles your static assets, you can easily optimize SVG files using svgo as a plugin. Here is how to do it.

Adding svgo as an esbuild plugin

  1. Add the svgo package to your project's package.json
  2. Adjust your esbuild.config.js like so:
const esbuild = require('esbuild')
const svgo = require('svgo')

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

RSpec: Executing specs by example id (or "nesting index")

There are several ways to run a single spec. I usually copy the spec file path with the line number of the example and pass it to the RSpec binary: bin/rspec spec/models/user_spec.rb:30 (multiple line numbers work as well: :30:36:68). Another is to tag the example with focus: true or to run the example by matching its name.

In this card I'd like to ...

Using Low-Level Prompts for High-Accuracy AI Coding

The key to unlocking the full potential of LLMs in coding lies in crafting precise prompts. The main challenge is learning how to structure prompts effectively to guide the model toward accurate results. Further evidence supporting this is the fact that Aider already writes ~70% of its own code (as of 02/2025). However, when starting out, your results may fall short of efficiently generating large portions of your code with the...

How to disable telemetry for various open source tools and libraries

Hint

If you are using our opscomplete.com hosting we can set all environment variables mentioned below for your deployment on request.

If you're lucky DO_NOT_TRACK=1 opts you out of CLI telemetry - it's not widely adopted. When you're using any of the libraries below, I'd rather opt out explicitly:

Yarn

https://yarnpkg.com/advanced/telemetry (Since: Version 2.2)

Disable for a project:

#...

Rails 8 introduces `params.expect`

The new params.expect method in Rails 8 improves parameter filtering, addressing issues with malformed input and enhancing security. It provides a cleaner, more explicit way to enforce the structure and types of incoming parameters.

What changed

  • Replaces require and permit: Combines both methods for concise parameter validation.
  • Explicit Array Handling: Requires double array syntax to define arrays of hashes, improving clarity.
  • Enhanced Validation: Ensures expected parameter structure, rejecting malformed input wi...

Rails console tricks

Also see the list of IRB commands.

Switching the context

Changes the "default receiver" of expressions. Can be used to simulate a "debugger situation" where you are "inside" an object. This is especially handy when needing to call private methods – just invoke them, no need to use send.

  • Switch to an object: chws $object
  • Reset to main: chws
  • Show current context: cwws (usually shown in IRB prompt)

[Technical details](https://technology.doximity.com/articles/the-hidden-gems-of-r...