Fix PNG colors in IE, old Safaris and new Firefoxes

Some browsers render PNG images with color profiles and other shenanigans, some don't. Remove some PNG chunks to render colors uniformly.

Geordi brings a command png-optimize which conveniently optimizes your PNGs for the web. See Github for a description

  • Single file and batch optimization is supported
  • optimize-png will overwrite the original files

Without Geordi

sudo apt-get install pngcrush
  • Single file:

    pngcrush -rem...

Generating test images on the fly via JavaScript

When you need test images, instead of using services like lorempixel or you may generate test images yourself. You can do this via JavaScript.

Here is an ES6 function that generates a simple SVG image and returns it as a data: URI. All browsers support SVG, and you can easily adjust it yourself.

function svgUri(text) {
  let svg = `
    <svg width="320" height="240" xmlns="">
      <rect x="0" y="0" width="320" height="240" style...

Grep through the DOM using the Capybara API

When your Cucumber feature needs to browse the page HTML, and you are not sure how to express your query as a clever CSS or XPath expression, there is another way: You can use all and find to grep through the DOM and then perform your search in plain Ruby.

Here is an example for this technique:

Then /^I should see an image with the filename...

Sprites with Compass

Using CSS sprites for background images is a technique for optimizing page load time by combining smaller images into a larger image sprite.

There are ongoing arguments on how useful this still is, as modern browsers become more comfortable to load images in parallel. However, many major websites still use them, for example amazon, [facebook](…

CSS: Giving text lines a background-color (with configurable line padding and margin)

The gist is:

  • wrap the text with a span
  • use line-height for the spacing between lines ("margin")
  • use box-shadow to control the line background size ("padding")



  box-shadow: 0 0 0 10px #fff
  background-color: #fff
  box-decoration-break: clone # Fix Firefox
  line-height: 2.2

→ [jsfiddle](…

Spreewald: Content-Disposition not set when testing a download's filename


  • You are not using javascript tests
  • The file is served from a public folder (not via controller)

Problem description

If you deliver files from a public folder it might be that the Content-Disposition header is not set. That's why the following spreewald step might raise an error:

Then I should get a download with filename "..."
expected: /filename="some.pdf"$/
     got: nil (using =~) (RSpec::Expectations::ExpectationNotMetError)


One solution…


Carrierwave: Built-in RSpec matchers

CarrierWave comes with some RSpec matchers which will make testing more comfortable. Let's say you have an Uploader like this:

class MyUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick

  # Create different versions of your uploaded files:
  version :small do
    process resize_to_fill: [100, 100]
  version :medium do
    process resize_to_fit: [200, nil]
  version :large do
    process resize_to_limit: [400, 400]


Imagine you have a class Movie with an attribute poster. In …


Common mistakes when storing file uploads with Rails

1. Saving files to a directory that is not shared between deploys or servers

If you save your uploads to a made up directory like "RAILS_ROOT/uploads", this directory goes away after every deploy (since every release gets a new). Also this directory is not shared between multiple application servers, so your uploads are randomly saved to one local filesystem or another. Fixing this afterwards is a lot of fun.

Only two folders are, by default, shared between our application servers and deployments: "RAILS_ROOT/storage" and `"RAILS…

Chrome: Making high-resolution website screenshots without add-ons

If you want to make a screenshot of a website that works well in print or on a high-DPI screen (like Apple Retina displays), here is how you can capture a high-resolution screenshot.

You can do this without an addon:

  • Open the website
  • If you have multiple monitoros:
    • Resize the Chrome window so it covers multiple monitors (in Linux you can hold ALT and resize by dragging with the right mouse button)
    • Zoom into the page using CTRL + and CTRL - so it covers most of the window area. Leave generous padding on the left and right so…

Carrierwave: Deleting files

TL;DR Use the #remove_<mounted_attribute>! method to delete attachments. Also, save the record after removing the file!

As you know, Carrierwave file attachments work by mounting an Uploader class to an attribute of the model. Though the database field holds the file name as string, calling the attribute will always return the uploader, no matter if a file is attached or not. (Side note: use #present? on the uploader to check if the file exists.)

class User < ApplicationRecord
  mount :avatar, AvatarUploader


CSS has a well-supported :empty selector

All browsers + IE9 know the CSS :empty selector. It lets you hide an element when it has no content, i.e. not even white space.

For instance, you have a badge displaying the number of unread messages in a red bubble with white text:

.unread-messages-bubble {
  background-color: red;
  border-radius: 10px;
  padding: 10px;
  color: white;

To hide that bubble entirely when there are no new messages:

.unread-messages-bubble:empty {
  display: none;

Note that the element must be…

External content

A Theme Switcher

Hack to implement an inverted "night mode" theme with a few lines of CSS.

Colors in images are preserved.

Rails: How to provide a public link in a mail

Lets say we have a user with a contract whereas contract is a mounted carrierwave file.

Now we want to send the link to the contract in a mail. For this use case join the root_url with the public contract path in the mailer view:

Plain text email

URI.join(root_url, @user.contract.url)

HTML email

link_to('Show contract', URI.join(root_url, @user.contract.url).to_s)

Note: You need to follow […


FileIO: Writing strings as Carrierwave uploads

When you have string contents (e.g. a generated binary stream, or data from a remote source) that you want to store as a file using Carrierwave, here is a simple solution.

While you could write your string to a file and pass that file to Carrierwave, why even bother? You already have your string (or stream).
However, a plain StringIO object will not work for Carrierwave's ActiveRecord integration:

>> Attachment.create!(file:
TypeError: no implicit conversion of nil into String

This is because Carrierwave ex…

Capybara: A step for finding images with filename and extension

This cucumber step is useful for testing an image (looking at the src of the image).

Then(/^I should see the image "([^"]*)"$/) do |filename_with_extension|
  expect(page).to have_css("img[src*='#{filename_with_extension}']")
Then I should see the image "placeholder.png"

Outline: Read more about how to test a uploaded file here, e.g. file downloads.


CarrierWave: How to remove GIF animation

When accepting GIF images, you will also accept animated GIFs. Resizing them can be a time-consuming task and will block a Rails worker until the image is processed.

Save yourself that trouble, and simply tell ImageMagick to drop any frames but the first one.

Add the following to your uploader class:

process :remove_animation


def remove_animation
  if content_type == 'image/gif'
    manipulate! { |image| image.collapse! }

You may also define that process for specific versions only (e….


Async control flow in JavaScript: Promises, Microtasks, async/await

Slides for Henning's talk on Sep 21st 2017.

Understanding sync vs. async control flow

Talking to synchronous (or "blocking") API

print('script start')
html = http_get('/foo')
print('script end')

Script outputs 'script start', (long delay), '<html>...</html>', 'script end'.

Talking to asynchronous (or "evented") API

print('script start')
http_get('foo', done: function(html) {
print('script end')

Script outputs `'script st…

Vagrant: create entry for box in .ssh/config

If you want to ssh into your vagrant box without switching into the project directory and typing vagrant ssh, you can also create an entry directly in ~/.ssh/config. This will allow you to use ssh <my-box> from anywhere. Simply paste the information provided by vagrant ssh-config to your ~/.ssh/config-File: vagrant ssh-config >> ~/.ssh/config


$ vagrant ssh-config
Host foobar-dev
User vagrant
Port 2200
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
PasswordAuthentication no