Encrypting messages with age (alternative to PGP)

age is a simple, modern and secure file encryption tool, format, and Go library.
It features small explicit keys, no config options, and UNIX-style composability.

Generally we are happy with GPG for encrypting emails. In case you are not happy with the CLI of GnuPG, this might be a tool you can use under the hood for encryption.

Unpoly 2: Don't try to download files through AJAX requests

Rails has the handy controller method send_file which lets us download files easily. We can decide whether the file should be downloaded (disposition: 'attachment') or shown in the browser (disposition: 'inline'). The default is disposition: 'attachment'.

Downloading files will not work when you are calling the controller action from an AJAX request. The browser will try to render the file and insert it in the DOM, which is never what you want.

Unpoly 2

Unpoly (sin...

Webpack: How to avoid multiple versions of jQuery

To avoid multiple versions of a package, you can manually maintain a resolutions section in your package.json. We recommend you to do this for packages like jQuery. Otherwise the jQuery library attached to window might not include the functions of your packages that depend on jQuery.

Note: This is only an issue in case you want to use a package functionality from window e.g. $(...).datepicker() from your dev console or any other javascript within the application.

Background

By default yarn will create a folder node_modules ...

Cucumber Factory: How to assign polymorphic associations

Cucumber factory supports polymorphic associations out of the box. Just keep in mind that you need to use named associations for this purpose.

class Person < ApplicationModel
  has_many :buildings, inverse_of: :owner
end

class Company < ApplicationModel
  has_many :buildings, inverse_of: :owner
end

class Building < ApplicationModel
  belongs_to :owner, optional: true, polymorphic: true
end

Works

Given there is a person with the name "Nice person"
  And there is a bui...

Cucumber features as documentation

Cucumber allows for prose in features and scenarios. Example:

Feature: Cancel account

  There are several ways to cancel a user account. Admins need to 
  do it in complex cases, but normally, users can do it themselves.
  
  Scenario: User cancels his own account
    
    Users should be able to cancel an account themselves, so the 
    admins do not need to do it.
    
    Given a user account for "willy@astor.de"
    When I sign in as "willy@astor.de"
    And I follow "Cancel account"
    Then I should see "Account canceled"...

Bookmarklet to facilitate generating new git branches for PivotalTracker Stories

This bookmarklet grabs a PivotalTracker story title, transforms it into a valid git branch name and automatically prepends your initials and an optional abbreviation (for better tab completion). It will output the following formats:

If you cancel the first dialog or confirm it without entering text:

git checkout -b kw/178298638-card-320-state-machines

If you enter an abbreviation (e.g. stm in this case):

git checkout -b kw/stm/178298638-card-320-state-machines

How to set it up:

  • in the attached file replace `YOUR_INITI...

Unobtrusive JavaScript helper to progressively enhance HTML

The attached compiler() function below applies JavaScript behavior to matching HTML elements as they enter the DOM.

This works like an Unpoly compiler for apps that don't use Unpoly, Custom Elements or any other mechanism that pairs JavaScript with HTML elements.

The compiler() function is also a lightweight replacement for our legacy [$.unobtrusive()](https://makandracards.com/makandra/4-unobtrusiv...

Using attribute event handlers with a strict Content Security Policy (CSP)

Given you have a strict CSP that only allows <script src> elements from your own domain:

Content-Security-Policy: script-src 'self'

This will block JavaScript handlers inlined as attribute into your HTML elements. Clicking on the following link will only log an error with a strict CSP:

<a href="javascript:alert('hello')">click me</a>
<a href="#" onclick="alert('hello')">click me</a>

Solution 1: Move the handler into your JavaScript

The recommended solution is to move the handler from the HTML to the allowed ...

RSpec: Debug flickering test suites with rspec --bisect

In modern default RSpec configurations, your tests are usually run in random order. This helps to detect "flickering" tests that only fail when run in a certain order.

The reason for this are tests that have side effects causing other tests to fail later. The hard part is to find the offending test.

Enter rspec --bisect:

  1. Say you have a flickering test that passes on its own, but you just saw it fail in a full test run. At the top of the RSpec output, you will see a message like Randomized with seed 12345. Take a note of the number....

How to use html_safe correctly

Back in the war, Rails developers had to manually HTML-escape user-supplied text before it was rendered in a view. If only a single piece of user-supplied text was rendered without prior escaping, it enabled XSS attacks like injecting a <script> tag into the view of another user.

Because this practice was so error-prone, the rails_xss plugin was developed and later integrated into Rails 3. rails_xss follows a different approach: Instead of relying...

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.

(How to prevent whitespace in HAML)

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

SSL/TLS - Typical problems and how to debug them

The linked article provides a description of commonly found problems with TLS and hints on debugging / solving them.

Don't forget: Automatically remove join records on has_many :through associations

Bad

# Given the following models

class Image < ActiveRecord::Base
  has_many :album_images
  has_many :albums, through: :album_images
end

class Album < ActiveRecord::Base
  has_many :album_images
  has_many :images, through: :album_images
end

# Join model
class AlbumImage < ActiveRecord::Base
  belongs_to :album
  belongs_to :image
end

Destroying a record in this setup will only remove the record itself, and leave orphaned join records behind.

image = Image.last
image.destroy # removes only the `image` record,
   ...

RSpec < 2.11: ActiveRecord scopes must be loaded before using the "=~" matcher

To test whether two arrays have the same elements regardless of order, you can use the =~ matcher in RSpec < 2.11:

actual_array.should =~ expected_array

If either side is an ActiveRecord scope rather than an array, you should call to_a on it first, since =~ does not play nice with scopes:

actual_scope.to_a.should =~ expected_scope.to_a

If you use RSpec >= 2.11 we recommend using the match_array or contain_exactly matchers instead of =~.
Use the eq matcher only if the order of records matters.

Default Arguments and Memoized

tl;dr: Avoid to memoize methods with default (keyword) arguments!

When you are using Memoized with default arguments or default keyword arguments, there are some edge cased you have to
keep in mind.

When you memoize a method with (keyword) arguments that have an expression as default value, you should be aware
that the expression is evaluated only once.

memoize def print_time(time = Time.now)
  time
end

print_time
=> 2021-07-23 14:23:18 +0200

sleep(1.minute)
print_time
=> 2021-07-23 14:23:18 +0200

When you memoize a met...

Using multiple MySQL versions on the same linux machine using docker

We had a card that described how to install multiple mysql versions using mysql-sandbox. Nowadays with the wide adoption of docker it might be easier to use a MySQL docker image for this purpose.

Create a new mysql instance

docker run --name projectname_db -e MYSQL_ROOT_PASSWORD=secret -p "33008:3306" -d --restart unless-stopped mysql:5.7

The port 33008 is a freely chosen free port on the host machine that will be used to establish a con...

How to extract a Ruby gem

The rubygems binary gem allows to extract a local gem with gem unpack GEMNAME. For more details see the official documentation.


This was useful for compliance checks, when it was necessary to check the license of the C-files in nokogiri.

CarrierWave: When your uploader generates filenames dynamically, use model.save! instead of uploader.recreate_versions!

If your Carrierwave uploader dynamically generates the filename (e.g. by incorporating a user's name), you must call model.save! after recreating versions.

uploader.recreate_versions! does not update the model with the stored filename.

Debugging AJAX requests with better_errors

better_errors is an awesome gem for enhanced error pages in development, featuring a live-REPL for some light debugging.

To debug the exception you got on an AJAX-Request, visit /__better_errors on your app's root path (e.g. http://localhost:3000/__better_errors). It shows the error page for the last exception that occurred, even when it has been triggered by an AJAX request.

CSS: How to force background images to scale to the container, ignoring aspect ratio

You can scale background images in CSS to the container size using background-size (Demo).

Commonly, we use contain or cover because we want to preserve the image's aspect ratio.
If you do not want to do that, simply provide scaling values for X and Y:

background-size: 100% 100%

(a simple 100% would mean 100% auto and respect the image's aspect ratio)

SVGs with a viewBox will force their aspect ratio

The above may not work for you when ...

Ruby: What extend and include do

All Rubyists should be familiar with the common definitions for include and extend. You include a module to add instance methods to a class and extend to add class methods. Unfortunately, this common definition isn’t entirely accurate. It fails to explain why we use instance.extend(Module) to add methods to an instance. Shouldn’t it be instance.include(Module)? To figure this out we’re going to start by discussing where methods are stored.

  • include: Adds methods from the provided Module to the object
  • extend: Calls include on the single...

Setting SASS variables as value for CSS custom properties

When using custom properties in your stylesheets, you may want to set a specific property value to an existing variable in your SASS environment. A pratical example would be a list of color variables that you've defined in colors.sass and that you would like to refer to in your stylesheets. However, simply assigning a variable will not work:

$my-great-blue: blue

:root
  --my-color: $my-great-blue

.sky
  background-color: var(--my-color)

The property value will not be valid and if you open the browser's inspection window, yo...

Headless Chrome: Changing the Accept-Language header is not possible

It seems like changing the HTTP_ACCEPT_LANGUAGE is not possible for a headless chrome.

  • On Ubuntu the headless Chrome derives the Accept-Language from the operation system
  • Adding the option options.add_argument('--lang=de') to the Capybara::Selenium::Driver has no effect
  • Adding the preference options.add_preference('intl.accept_languages', 'de') to the Capybara::Selenium::Driver has only effects if the --headless option is skipped (see bug ticket #775911)
  • Cha...

Selenium: Network throttling via Chromedriver

You can throttle the network in your headless chrome via Selenium. This might be useful for debugging issues with flaky integration tests or slow page simulations.

page.driver.browser.network_conditions = {offline: false, latency: 5, download_throughput: 2 * 1024, upload_throughput: 2 * 1024}

The settings will match to the following UI component in Chrome:

Image

Were the values for the default profiles might match the values from this post:

**S...