Postgres in Alpine docker container: sorting order might differ
In CI test runs I noticed that string sorting order changed after switching from a debian-based PostgreSQL docker image to one that is based on Alpine Linux.
Debian image sorting: bar Bar foo Foo
Alpine image sorting: Bar Foo bar foo
Explanation
Alpine Linux is a very slim linux distribution that results in small docker image sizes (roughly 100MB instead of 150MB), so it's a popular choice. However, it does not have all comman locales installed and does not use all locales that a user installs by default.
Postgres orders string co...
Node: How to run a globally installed package with npx
You can tell npm to install a package globally with npm -g install @puppeteer/browsers. However, it seems that its not possible that npx can run commands from global packages without referencing the global package path.
Example
Installing @puppeteer/browsers globally:
$ npm -g install @puppeteer/browsers
The globally installed package @puppeteer/browsers can not be access via npx:
$ npx --no-install @puppeteer/browsers
npm ERR! canceled # Error message when package is not installed
But it is installed g...
CarrierWave: Processing images with libvips
When you write your next CarrierWave uploader, consider processing your images with libvips instead of ImageMagick.
Reasons for libvips
There are several upsides to using libvips over ImageMagick:
- libvips is considerably faster and uses less memory.
- ImageMagick has a large attack surface that has repeatedly caused security incidents in the past (compare [ImageMagick CVEs](https://www....
Chromedriver: Connect local chromedriver with docker
Debugging your integration tests, that run a headless Chrome inside a docker image, is tricky.
In many cases you can connect your Chrome to a remote docker container like docker-selenium, which should be the preferred way when you try to inspect a page within your integration test.
Otherwise you might be able to start your docker container with --net=host and access your local chromedriver in the host address space host.docker.internal.
If both options above don't work for you here is a...
Preventing users from uploading malicious content
When you allow file uploads in your app, a user might upload content that hurts other users.
Our primary concern here is users uploading .html or .svg files that can run JavaScript and possibly hijack another user's session.
A secondary concern is that malicious users can upload executables (like an .exe or .scr file) and use your server to distribute it. However, modern operating systems usually warn before executing files that were downloaded from t...
Rails: Fixing ETags that never match
Every Rails response has a default ETag header. In theory this would enable caching for multiple requests to the same resource. Unfortunately the default ETags produced by Rails are effectively random, meaning they can never match a future request.
Understanding ETags
When your Rails app responds with ETag headers, future requests to the same URL can be answered with an empty response if the underlying content ha...
CSP: strict-dynamic
tl;dr
The
strict-dynamicsource list keyword allows you to simplify your CSP policy by favoring hashes and nonces over domain host lists.The key super power of
strict-dynamicis that it will allow to load additional scripts via non-"parser-inserted" script elements.
For unsupported browsers, your script can be made backwards compatible by doing something like this:
script-src 'nonce-rAnd0m' 'strict-dynamic' https: 'self'
default-s...
Using the Oklch color space to generate an accessible color palette
The linked content describes:
- The different color space of Oklch and RGB/HSL (HDR colors)
- The advantage of Oklch when you change a base color and your derived colors will keep the same assertions on contrast level
Warning
This feature landed in browsers at the end of 2022. According to our support policy this will become generally usable starting Dec 2024.
The oklch() functional notation expresses a given color in the Oklch color space. It has the same L axis as oklab(), but uses polar coordinates C (Chroma) and H (Hue).
Sour...
SASS: Reusing styles from other files
SASS has an @extend keyword to inherit styles.
.alert
color: red
&.-framed
border: 1px solid red
padding: 5px
&.-homepage
@extend .-framed
border-width: 5px
When compiling, SASS will simply join the selectors. Note how .-homepage is written where .-framed was defined:
...
.alert.-framed, .alert.-homepage {
border: 1px solid red;
padding: 5px;
}
.alert.-homepage {
border-width: 5px;
}
Warning
Unfortunately, this does...
How to turn images into inline attachments in emails
Not all email clients support external images in all situations, e.g. an image within a link. In some cases, a viable workaround is to turn your images into inline attachments.
Note
Rails provides a simple mechanism to achieve this:
This documentation makes it look like you have to care about these attachments in two places. You have to create the attachment in t...
Carrierwave: Custom file validations inside custom Uploaders
Carrierwave's BaseUploader can have some validations that you can use by overriding a certain method, which's expected name is hard coded. A popular example is extension_allowlist, which returns an array of strings and let's you only upload files that have a filename with an extension that matches an entry in that array. Another useful validation can be size_range, which gives you a little bit of control over how your storage gets polluted.
This is often good enough, but some times you need to validate special cases.
Validations t...
git: find the version of a gem that releases a certain commit
Sometimes I ran across a GitHub merge request of a gem where it was not completely obvious in which version the change was released. This might be the case for a bugfix PR that you want to add to your project.
Git can help you to find the next git tag that was set in the branch. This usually has the name of the version in it (as the rake release task automatically creates a git tag during release).
git name-rev --tags <commit ref>
Note
The more commonly used
git describecommand will return the last tag before a c...
How to make your git aliases work with both master and main
The linked article found a simple way to rewrite legacy git aliases to make them work with differently named default branches
- Step 1: Decide which is the most common default branch name of your projects, e.g.
master. Define it as the globalinit.defaultBranchgit configuration :
git config --global init.defaultBranch master
- Step 2: Overwrite the value in each project directory that uses different defaults
# cd /path/to/project, then run:
git config ...
How to develop designs for an enterprise customer
Usually, design development starts with drafts, sketches and prototypes. These are reviewed, refined and iterated until the final design is ready – shiny, accepted and ready for implementation. I believe this works well when you get to work with the final decider in person.
However, this approach is not successful when the customer has complex internal structures ("Enterprise"). While the drafts and iterations might be all approved by the department you're working directly with ("Fachbereich"), deciders further up the hierarchy (the CEO, po...
Heads up: network requests `Kernel#open` are not mocked with VCR
We usually rely on VCR and WebMock to prevent any real network connection when running our unit tests.
This is not entirely true: They are both limited to a set of HTTP libraries listed below (as of 2022). Direct calls to Kernel#open or OpenURI#open_uri are not mocked and will trigger real network requests even in tests. This might bite you e.g. in [older versions of CarrierWave](https://github.com/carrierwaveuploader/carrierwave/blob/0.11-stable/lib/carrierwave/upl...
A modern approach to SVG icons
You have some SVG files you want to use as icons on your website. How would you embed them?
Common options are:
- Use them with an image:
<img src='path-to-icon.svg'> - Embed them inline with
<svg>$ICON</svg> - Embed them using CSS and
background-image: url(path-to-icon.svg)or evenbackground-image: url(data:$ICON). - Build your own icon font.
All of these have drawbacks:
- Image and
background-imagedo not allow to recolor the image using CSS. - Inline-
<svg>are unnecessary work for the server and are...
Using path aliases in esbuild
In esbuild, you usually import other files using relative paths:
import './some-related-module'
import `../../utils/some-utility-module`
import `../../../css/some-css.sass`
This is totally fine if you import closely related files, but a bit clunky when you're trying to import some "global" module, like a utility module. When moving a file, your imports also need to change.
To get around this, esbuild support a mechanism first introduced in TypeScript called "path aliases". It works like this:
First, you create a file called `js...
How to see how many inotify instances are used by each process
As a developer you may have many tools watching your project for changes: Your IDE, Webpack, Guard, etc. This is often done with an inotify watcher. If you have too many inotify instances you may run into limits of your operating system.
To find out which process is using them all up you can run:
sudo find /proc/*/fd/ -type l -lname "anon_inode:inotify" -printf "%hinfo/%f\n" | xargs grep -cE "^inotify" | column -t -s:
You will get a list like:
/proc/3753/fdinfo/7 1
/proc/3774/fdinfo/7 1
/proc/4034/fdinfo/12 14
/pr...
Inspect and Debug CSS Flexbox and Grid Layouts by using the Layouts Tab in Dev Tools
tl;dr
In Chrome DevTools in the Layouts tab you have handy options to debug CSS Flexbox and Grid. Including:
- Display size and lines along with labels
- Changing their attributes
- Change how overlay is colored and fastly switch nested elements in the Elements panel
This guide will only cover some example gif recordings on how to use with Grid, since it's basically straight forward to apply this for Flexbox by yourself afterwards.
For this purpose a the link to documentation and a simple code pen have been added...
Converting SVG to other vector formats without Inkscape
If you need to convert an SVG source to PS or EPS, the most common suggestion on the interwebs is to use Inkscape from the commandline.
Inkscape is a fairly resource-heavy tool with lots of dependencies. A great alternative for converting is CairoSVG.
CairoSVG is available on most Linux distros through their package management systems, e.g. apt install cairosvg on Ubuntu.
It has few dependencies (most importantly Python 3 and some related packages, but really not much)...
Generating and streaming ZIP archives on the fly
When your Rails application offers downloading a bunch of files as ZIP archive, you basically have two options:
- Write a ZIP file to disk and send it as a download to the user.
- Generate a ZIP archive on the fly while streaming it in chunks to the user.
This card is about option 2, and it is actually fairly easy to set up.
We are using this to generate ZIP archives with lots of files (500k+) on the fly, and it works like a charm.
Why stream downloads?
Offering downloads of large archives can be cumbersome:
- It takes time to b...
CSS: The inset CSS shorthand
The inset CSS property is a shorthand that corresponds to the top, right, bottom, and/or left properties. It has the same multi-value syntax of the margin shorthand.
Example
<div class="outer">
<div class="inner">
Some text
</div>
</div>
.outer {
background-color: cyan;
position: relative;
width: 500px;
height: 500px;
}
Top, right, bottom and left
https://jsfiddle.net/jqx68wem/
.inner {
background-color: darkCyan;
position: absolute;
top: 10px;
right: 10px;
bottom: 10p...
How to debug file system access in a Rails application
It might sometimes be useful to check whether your Rails application accesses the file system unnecessarily, for example if your file system access is slow because it goes over the network.
The culprit might be a library like carrierwave that checks file existence or modification times, whereas your application could determine all this from your database.
Introducing strace
One option it to use strace for this, which logs all system calls performed by a process.
To do this, start your rails server using something like
DISA...
Why am I getting different results working with SVG files and ImageMagick?
When you are working with SVG files and ImageMagick you can get different results on different machines depending on which additional packages you have installed.
From: http://www.imagemagick.org/script/formats.php
ImageMagick utilizes inkscape if its in your execution path otherwise RSVG. If neither are available, ImageMagick reverts to its internal SVG renderer.