Git: Parsing large diffs as a human

I just finished migrating a project from the Asset Pipeline to Webpacker, this is what my diff to master looks like:

5.825 files changed, 44.805 insertions(+), 529.948 deletions(-)
warning: inexact rename detection was skipped due to too many files.
warning: you may want to set your diff.renameLimit variable to at least 5134 and retry the command.

There is no way me or my peer reviewer is able to parse 500k+ lines of code. Fortunately, git has ...

Efficiently add an event listener to many elements

When you need to add a event listener to hundreds of elements, this might slow down the browser.

An alternative is to register an event listener at the root of the DOM tree (document). Then wait for events to bubble up and check whether the triggering element (event.target) matches the selector before you run your callback.

This technique is called event delegation.

Performance considerations

Because you only register a single listener, registering is ...

Ruby: How to load a file with a known encoding

In case Ruby does not detected the expected encoding of a file automatically you can specify the known encoding manually.

Example with File.open

file = File.open('some.bin', encoding: Encoding::ASCII_8BIT)
text = file.read
text.encoding => #<Encoding:ASCII-8BIT>

Example with File.read

text = File.read('some.bin', encoding: Encoding::ASCII_8BIT)
text.encoding => #<Encoding:ASCII-8BIT>

More details about the encoding of strings in Ruby can be found [here](https://makandracards.com/makandra/474671-guide-to-string-encodi...

Fixing memory leaks in the browser

In my experience, the most common sources of memory leaks are APIs like these:

  • addEventListener. This is the most common one. Call removeEventListener to clean it up.
  • setTimeout / setInterval. If you create a recurring timer (e.g. to run every 30 seconds), then you need to clean it up with clearTimeout or clearInterval. (setTimeout can leak if it’s used like setInterval – i.e., scheduling a new setTimeout inside of the setTimeout callback.)
  • IntersectionObserver, ResizeObserver, MutationObserver, etc. The...

How to communicate between processes in Ruby with sockets

In Ruby you can communicate between processes with sockets. This might be helpful in tests that validate parallel executions or custom finalization logic after the garbage collector. Here is an example how such an communication will look like:

require 'socket'
BUFFER_SIZE = 1024

# DGRAM has the advantage that it stops reading the pipe if the next messages starts. In case the message size is larger than the
# BUFFER_SIZE, you need to handle if you are reading another part of the current message or if you already reading the
# next mess...

ExceptionNotification: Fix DNS lookup before plugins call external APIs

The ExceptionNotification has plugins that talk to external APIs rather then just sends emails, like microsoft teams or slack. You might encounter that no exceptions are delivered, which can be dangerous.

To prevent getting into trouble, simply add require 'resolv-replace' on top of your to your initializers/exception_notification.rb file:

require 'resolv-replace'
require 'exception_notification/rails'

ExceptionNotification.configure do |config|
  ...
end

This calls the Ruby DNS resolver before configuring `ExceptionNot...

Call original method when monkey patching

Ruby offers monkey patching methods in order to change the behavior of a library if there's no better way.

We can call the method we're overriding inside our monkey patch:

class Foo
  def bar(argument)
    'Hello' + argument
  end
end 

module FooExtensions
  def bar
    super(' in my') + ' World'
  end
end

class Foo
  prepend FooExtensions # the only change to above: prepend instead of include
end

Foo.new.bar # => 'Hello in my...

Transporting blank values in URL queries

URLs can transport key/value pairs ("parameters") using this syntax:

/path?foo=bar

If the value is blank, mind these subtle differences:

URL Meaning
/path?foo= Parameters have a key foo. Its value is an empty string.
/path?foo Parameters have a key foo. Its value is null.
/path Parameters have no key foo.

How to build a fully custom TinyMCE 5 dialog

TinyMCE is a WYSIWYG editor which is quite customizable.


  1. Add a custom button to the tinyMCE toolbar and tell tinyMCE to open a dialog with the route to your dialog's view.
tinymce.init({
  // ...
  toolbar: 'myCustomButton',
  setup: function(editor) {
      editor.ui.registry.addButton('myCustom Button', {
        ...

How to test inside iframes with cucumber / capybara

When testing with Cucumber / Caypbara, iframes are ignored, so you can't interact with them.

To interact with your iframe, you have to explicitly tell your driver to use it.
You can reference your iframe either through it's id, or if none given, by it's number:

When /^(.*?) inside the (.*?). iframe$/ do |nested_step, frame_number|
  page.within_frame(frame_number.to_i) do
    step nested_step
  end
end

When /^(.*?) inside the (.*?). iframe:$/ do |nested...

Ruby < 2.4: Downcasing or upcasing umlauts

Using .downcase or .upcase on strings containing umlauts does not work as expected in Ruby versions before 2.4. It leaves the umlauts unchanged:

"Über".downcase
=> "Über"

"Ärger".downcase
=> "Ärger"

The very same applies for french accents (Thanks Guillaume!):

"Être ou ne pas être, telle est la question".downcase
=> "Être ou ne pas être, telle est la question"

Obviously, this leads to problems when comparing strings:

"Über".downcase == "über"
=> false

In Rails you can use ActiveSupports' [multib...

Ruby: How to keep split delimiter (separate, or as part of substrings)

Ruby's String#split returns an array of substrings from the given string. Usually, this is missing the split characters:

>> 'user@example.com'.split('@')
=> ["user", "example.com"]

If you want to join those parts later on, you might know the split character and can just use it to join explicitly.
But if you split by a regular expression (for a set of split characters) that information is lost:

>> 'user@example.com'.split(/[@\.]/)
=> ["user", "example", "com"]

You can use a capture group to make those characters ...

SSHKit 1.9.0 failure for Capistrano deploy

SSHKit 1.9.0 might fail with the following error, when trying to deploy a Rail application. Upgrading the gem to version 1.21.0 fixed the issue.

Traceback (most recent call last):
	17: from /home/user/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/sshkit-1.9.0/lib/sshkit/runners/parallel.rb:12:in `block (2 levels) in execute'
	16: from /home/user/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/sshkit-1.9.0/lib/sshkit/backends/abstract.rb:29:in `run'
	15: from /home/user/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/sshkit-1.9....

Whenever requires you to set the application attribute in the Capistrano config

Whenever requires you to set the application attribute in your Capistrano configuration. Otherwise your cronjobs are created multiple times.

Example entry in config/deploy.rb:

set :application, 'some-app' # allows "set :whenever_identifier, ->{ "#{fetch(:application)}_#{fetch(:stage)}" }" to work as expected

Good

Then the crontab -l output will look like this:

# Begin Whenever generated tasks for: som...

HowVideo.works

This is an informational site about video and how it works. We started by talking about Playback, next we added content about Delivery. Stay tuned for more about Processing and Capture.

Missing certificates for rubygems and bundler in Ruby 1.8.7

Using Ruby 1.8.7 you will not be able to use the maximum versions Rubygems 1.8.30 and Bundler 1.17.3 with https://rubygems.org/ anymore. This is a result of a server certificate on December 5th, 2020. The resulting errors will look like following:

  • TypeError: can't modify frozen object
  • Could not verify the SSL certificate for https://rubygems.org/*
  • Bundler::Fetcher::CertificateFailureError: Could not verify the SSL certificate for https://index.rubygems.org/versions.
  • `Error fetching data: hostname was not m...

A few recent CSS properties

  • Feature Queries (Edge 12+): Similar to @media queries, @supports blocks can be scoped to browsers that support a given declaration. There is CSS.supports() to do the equivalent in Javascript.

  • backdrop-filter (Edge 17+, but not FF): Applying filters to what is visible through an element.

  • [touch-action](https://d...

liquidprompt: A full-featured & carefully designed adaptive prompt for Bash & Zsh

Liquid Prompt gives you a nicely displayed prompt with useful information when you need it. It shows you what you need when you need it. You will notice what changes when it changes, saving time and frustration. You can even use it with your favorite shell – Bash or zsh.

liquidprompt Examples

Configuring Webpacker deployments with Capistrano

When deploying a Rails application that is using Webpacker and Capistrano, there are a few configuration tweaks that optimize the experience.

Using capistrano-rails

capistrano-rails is a Gem that adds Rails specifics to Capistrano, i.e. support for Bundler, assets, and migrations. While it is designed for Asset Pipeline (Sprockets) assets, it can easily be configured for Webpacker. This brings these features to the Webpacker world:

  • Automatic removal of expired assets
  • Manifest backups

Testing ActiveRecord validations with RSpec

Validations should be covered by a model's spec.

This card shows how to test an individual validation. This is preferrable to save an entire record and see whether it is invalid.

Recipe for testing any validation

In general any validation test for an attribute :attribute_being_tested looks like this:

  1. Make a model instance (named record below)
  2. Run validations by saying record.validate
  3. Check if record.errors[:attribute_being_tested] contains the expected validation error
  4. Put the attribute into a valid state
  5. Run...

Using the alt attribute and the figcaption element in HTML

The linked blog post contains some background information about the alt attribute and the figure / figcaption element. It is interesting, that a figure is not only for images but also for captions, code snippets, quotations and more.

How to remove entries from the bash history

Sometimes you accidentally generate entries in the bash history that you do not want to have there (e.g. commands with credentials).
Here's how to remove single entries.

You can look at the bash history with the history command.
To see e.g. the last 5 entries, use history | tail -n 5:

>history | tail -n 5
 1994  my-secret-command
 1995  cd xyz-mnt/
 1996  ls
 1997  cd appliance/
 1998  cd ..

Each entry has a number. You can use that to delete it: history -d 1994. Note that as you delete entries, the numbers of the following...

How to have a target=_blank link open with DevTools open

In the tab where you need it, open Chrome DevTools with F12, open settings with F1, scroll down to the "Global" section and check "Auto-open DevTools for popups".

When you follow a link with target=_blank within that tab, DevTools will be open and you can inspect e.g. request headers.

How to fix: Pasting in IRB 1.2+ is very slow

IRB 1.2 (shipped with Ruby 2.7, but works on 2.5+) brings pretty syntax highlighting and multiline cursor navigation. However, pasting longer contents is incredibly slow. You can fix that by disabling said features. [1]

Ruby 3.0.0-pre2 solved the issue (however, the fix does not appear to be included in IRB 1.2.6, it must be Ruby itself).

Option 1:

Add a command line flag when opening an IRB:

irb --nomultiline

This also works on modern Rails...