ActiveJob Inline can break the autoloading in development

We figured out, that ActiveJob Inline might lead to autoloading problems in development. The result was an exception when running an import script, which delivers async mails.

A copy of XXX has been removed from the module tree but is still active! (ArgumentError)

Our fix was to use .deliver_now and not .deliver_later (this is not a general fix, but it was okey for us). Below there are some debug hints which helped us to locate the problem:

  • We placed a pry debugger in [ActiveSupport#clear](https://github.com/rails/rails/blob...

Fixing "identify: not authorized"

Ubuntu has decided to disable PDF processing because ImageMagick and the underlying Ghostscript had several security issues.

When your Ghostscript is up to date (and receiving updates regularly), you can safely reactivate PDF processing on your computer like this:

  1. Open /etc/ImageMagick-6/policy.xml (requires sudo)
    • For older versions of Ubuntu (or possibly ImageMagick), the path is /etc/ImageMagick/policy.xml
  2. Remove/Comment lines after <!-- disable ghostscript format types -->

If you need ...

An incomplete guide to migrate a Rails application from paperclip to carrierwave

In this example we assume that not only the storage gem changes but also the file structure on disc.

A general approach

Part A: Create a commit which includes a script that allows you to copy the existing file to the new file structure.

Part B: Create a commit which removes all paperclip logic and replace it with the same code you used in the first commit

Part A

Here are some implementation details you might want to reuse:

  • Use the existing models to read the files from
  • Use your own carrierwave models to write t...

Rails: How to check if a certain validation failed

If validations failed for a record, and you want to find out if a specific validation failed, you can leverage ActiveModel's error objects.
You rarely need this in application code (you usually just want to print error messages), but it can be useful when writing tests.

As an example, consider the following model which uses two validations on the email attribute.

class User < ApplicationRecord
  validates :email, presence: true, uniqueness: true
end

Accessing errors

Let's assume we have a blank user:

user = Us...

Printing background color of elements

Browsers' printing methods usually don't print background colors. In most cases this is the desired behavior, because you don't want to spend tons of ink printing the background of a web page. But in some cases you want to print the background color of elements, e.g. bars of a chart. For those elements you need to set the following CSS styles:

-webkit-print-color-adjust: exact; /* Chrome and Safari */
color-adjust: exact; /* Firefox */

Another case is printing of white text. When removing background colors, chances are white text n...

Capistrano task to tail remote application logs of multiple servers

When your application is running on a multi-server setup, application logs are stored per server (unless you choose a centralized logging solution).
Here is a Capistrano task that connects to all servers and prints logs to your terminal like this:

$ cap production app:logs
00:00 app:logs
      01 tail -n0 -F /var/www/your-application/shared/log/production.log | while read line; do echo "$(hostname): $line"; done
      01 app01-prod: Started GET "/sign_in" for 1.2.3.4 at 2018-04-26 11:28:19 +0200
      01 app01-prod: Proc...

Understanding IRB warning "can't alias ... from ..."

Sometimes, the IRB prints a warning during boot:

irb: warn: can't alias source from irb_source.

Explanation

During boot, the IRB creates many aliases to give the user quick access to irb functions like source-ing a file.

However, if IRB's context already responds to the alias it wants to create, it will no...

How to resize your boot partition when there is an encrypted partition after it

Boot partitions from installations prior to the 16.04 era are terribly small. When you install updates and encounter errors due to a full /boot partition, consider risizing it.

If you can't do the steps described below, ask someone experienced to help you out.
This has worked 100% so far. 1 out of 1 tries. ;)

Scenario A: There is unassigned space on your physical drive

When there is some unpartitioned space on your drive, increasing the size of /boot is actually very easy (even though the list below is rather long). It only takes a...

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: StringIO.new(contents))
TypeError: no implicit conversion of nil into String

This is because Carrierwav...

Upgrading a Rails app to Cucumber 3

Upgrade gems

You need to update a lof gems. Make sure you don't have any version constraints in your Gemfile or your bundle update won't do anything!

Upgrade cucumber_priority:

bundle update cucumber_priority

Upgrade spreewald:

bundle update spreewald

Upgrade cucumber_factory:

bundle update cucumber_factory

Upgrade parallel_tests:

bundle update parallel_tests

Even on the latest version, parallel_tests will print some deprecation warnings due to using an older formatter A...

Advantages of using appname.daho.im:3000 over localhost:3000

Running rails server will start a local server that you can access via http://localhost:3000.

When you are working on multiple web apps, they will likely set cookies with generic names on localhost. This is annoying, since you will sign out your current user whenever you switch to another app.

A better way is to use our own daho.im service. All daho.im subdomains resolve to your local IP (127.0.0.1). That means you can use a different hostname for different apps, and you will stay logged in in each app:

http://foo-ap...

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 a little padding on the left and right so...

Form letters with LibreOffice Writer

This is painful. Consider using Microsoft Office or switching careers. If you need to write < 20 letters consider doing it manually.

So you didn't listen and here it comes:

  1. Ignore the Mail Merge Wizard. It will crash or destroy your document.
  2. Export your addresses, recipient names, etc. as a .ods spreadsheet (.xls, .xlsx, .ods). Use any columns that work for you, but be consistent. I like to use one column for the address, one column for the salutation line.
  3. Import the spreadsheet as an address book source: *Tools => Add...

How to fix HTML elements being cut off when printing

When you print (or print preview) and elements are cut off (e.g. after 1st page, or "randomly") you should check your CSS rules for these:

  • Is there an element with "display: inline-block" that surrounds your content? Make sure it has "display: block" for printing.
    This primarily affects Firefox and Internet Explorer. Chrome seems to be able to handle inline-block elements in most cases.

  • Does the element itself, or a container, define "overflow: hidden"? Use "overflow: auto" (or maybe "overflow: visible") instead.

  • Is th...

Cucumber: Identifying slow steps that drag down your test speed

In most projects I know, Cucumber test suite speed is not an issue. Of course, running 350 features takes its time, but still each test for itself is reasonably fast. There is nothing you can do to fundamentally speed up such a test (of course, you should be using parallel_tests).

However, in projects that go beyond clicking around in a web GUI and checking results, there might be various measures to speed things up. Katapult tests for example could be sped up more than 4 times by re...

RSpec: Running examples by name (or running a single shared example)

When an Rspec example fails, I usually investigate by running that example again using rspec <file:line>. However, this does not work with shared examples, since Rspec doesn't know in which context the shared example should be run.

But there is a different way: You can run the shared example using the -e, --example option. It takes a string value and runs all scenarios containing that substring in their full description.

This allows you to run a single uniquely named example, all examples with
similar names, all the examples in a u...

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

Precondition

  • 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)

Solution

One solution...

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 = get('/foo')
print(html)
print('script end')

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

Talking to asynchronous (or "evented") API

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

Script outputs 'script start', 'script end', (long ...

How to fix broken font collisions in wkhtmltopdf

If you are using PDFKit / wkhtmltopdf, you might as well want to use custom fonts in your stylesheets. Usually this should not be a problem, but at times they include misleading Meta-information that leads to a strange error in the PDF.

The setup

  • The designer gave you two fonts named something like BrandonText-Regular and BrandonText-Bold. (With flawed Meta-information)
  • You have a HTML string to be rendered by PDFKit
  • For demonstration purposes, this strin...

Custom Ruby method Enumerable#count_by (use for quick statistics)

I frequently find myself needing a combination of group_by, count and sort for quick statistics. Here's a method on Enumerable that combines the three:

module Enumerable
  def count_by(&block)
    group_by(&block)
      .transform_values(&:count)
      .sort_by(&:last)
      .to_h
  end
end

Just paste that snippet into a Rails console and use #count_by now!

Usage examples

  • Number of email addresses by domain:
> User.all.count_by { |user| user.email.sub /^.*@/, '' }
=> { "sina.cn"=>2, ..., "hotmail.com"=>128...

Quickly printing data in columns on your Ruby console

Dump this method into your Ruby console to quickly print data in columns. This is helpful for e.g. comparing attributes of a set of Rails records.

def tp(objects, *method_names)
  terminal_width = `tput cols`.to_i
  cols = objects.count + 1 # Label column
  col_width = (terminal_width / cols) - 1 # Column spacing

  Array(method_names).map do |method_name|
    cells = objects.map{ |o| o.send(method_name).inspect }
    cells.unshift(method_name)

    puts cells.map{ |cell| cell.to_s.ljust(col_width) }.join ' '
  end

  nil
end

Usag...

How to view Image Metadata on the Linux Command Line with ImageMagick

ImageMagick has a command line tool called identify which can read image metadata:

>identify -verbose DSC00136.JPG
Image: DSC00136.JPG
  Format: JPEG (Joint Photographic Experts Group JFIF format)
  Class: DirectClass
  Geometry: 5472x3648+0+0
  Resolution: 350x350
  Print size: 15.6343x10.4229
  Units: PixelsPerInch
  Type: TrueColor
  Endianess: Undefined
  Colorspace: sRGB
  Depth: 8-bit
  Channel depth:
    red: 8-bit
    green: 8-bit
    blue: 8-bit
  Channel statistics:
    Red:
      min: 0 (0)
      max: 255 (1)
      mean: 11...

Things you probably didn’t know you could do with Chrome’s Developer Console

Collection of useful tools in the Chrome JavaScript console.

Make the whole page editable

This is not special to Chrome, but still a clever thing:

document.body.contentEditable=true 

Taking time

You can easily measure the time on the console with named timers:

console.time('myTime'); // Start timer
console.timeEnd('myTime'); // End timer and print the time

Reference previously inspected elements (from the Elements panel)

Variables $0, $1, ... $n reference the nth-last inspected Element. $0 ...

Bundler: Gemfile.lock is corrupt & gems are missing from the DEPENDENCIES section

So you're getting this failure when running bundle install on an older project:

Your Gemfile.lock is corrupt. The following gems are missing from the DEPENDENCIES section: 'archive-tar-minitar' 'hoe' 'rcov'

This happens when you are using a new version of Bundler with a project that was bundled with a very old version of Bundler. For reasons unknown, the Bundler dependency API returns different dependencies for some gems (like ruby-debug or rainpress) than the dependencies found in the downloaded gemspecs. While old versi...