How to enable template coverage support for simplecov

Since Ruby 3.2.0 you can measure coverage support for eval statements and support has been added for the simplecov gem as well.

This allows to track coverage across ruby templates such as haml, erb, ...

Simply set this within simplecov

SimpleCov.start do
  enable_coverage_for_eval
end

SVGO: SVG Optimizer

SVG files are often much larger than necessary, containing comments, metadata, hidden elements etc.

Optimize them with this tool.

Note that for a properly scaling SVG, you need to keep the viewBox attribute. There's an option --disable=removeViewBox for this.

FactoryBot: Passing attributes to associated records using transient attributes

FactoryBot.define do

  factory :parent do
    transient do
      child_name nil
      child_allowed_to_drive false
    end
    
    child do
      association(:child, name: child_name, allowed_to_drive: child_allowed_to_drive)
    end
  end

  factory :child do
    name 'Child'
    allowed_to_drive false
  end

end

# Usage
daughter = FactoryBot.create(:parent, child_name: 'Lisa').child
daughter.name # => 'Lisa'
daughter.allowed_to_drive? # => false

son = FactoryBot.create(:parent, child_name: 'Benedikt', child_allowed_to_drive: tr...

Project management best practices: Stories

We organize our daily work with stories in Pivotal Tracker.

Story format

A good story needs to be precise. It should be very clear what is part of a story, and what is not. If there are different expectations between the person who writes and who implements a story, there will be rejects.

To this end, we use a consistent format for stories that looks like this:

Story: Autocomplete

As a journalist, I want to have an autocomplete in the search bar, to have a more efficient way to find articles.

Acceptance criteria
===...

Deterministic ordering of records by created_at timestamp

Creating records in specs can be so fast that two records created instantly after one another might have the same created_at timestamp (especially since those timestamps don't have an indefinitely high resolution). When ordering lists by timestamps, you should therefore always include a final order condition using the primary key of the table.

class Photo < ActiveRecord::Base
  scope :by_date, -> { order('created_at DESC, id DESC') }
end

Photo.by_date

Remember to include the id field in the database index.

Rails migration: Change a column type without losing the content

The change_column method for rails migrations support casting with a custom SQL statement. This allows us to change a column type and keep the former content as the new type. This way, we can for example prepare an address number column to hold German address numbers, which can contain letters:

Example (in most cases not a good idea!)

class ChangeAnIntegerColumnToString < ActiveRecord::Migration[6.1]
  def up
    change_column :users, :address_number, 'varchar USING CAST(rating AS varchar)'
  end

  def down
    change_column ...

CSS: CSS Container Queries

Container queries enable you to apply styles to an element based on the size of the element's container. If, for example, a container has less space available in the surrounding context, you can hide certain elements or use smaller fonts. Container queries are an alternative to media queries, which apply styles to elements based on viewport size or other device characteristics.

This feature is now stable across browsers.

Warning

This feature landed in browsers at the end of 2022. According to our support policy this will become ge...

Creating a sample video with ffmpeg

If you need a sample video with certain properties for a test you can create one using ffmpeg.
You might want a very low bitrate file to speed up processing in your test. (e.g. you only care about the length, then you can create a video with a very low resolution and framerate)

Create a 21s video with 1fps and 10x10 resolution:
ffmpeg -t 21 -s 10x10 -r 1 -f rawvideo -pix_fmt rgb24 -i /dev/zero sample_21_seconds.mp4

Option Explanation
-t 21 set the length to 21s
-s 10x10 set the resolution the 10 by 10 p...

How to split up a git commit

Quick steps

  1. git rebase -i -> mark your commit with edit
  2. git reset HEAD~ (remove the marked commit, but keep its changes)
  3. Make several commits
  4. git rebase --continue

Detailed instructions

Basically, you will review the last n commits and stop at the splittable commit. Then you'll undo that commit and put its changes into new commits at your liking.

  1. Review commits (rebase)

    git rebase -i HEAD~3
    # or
    git rebase -i origin/master
    

    Git will give you a list of commits, younge...

Shorthand function properties in ES6

Here is an ES5 object literal with two string properties and a function property:

let user = { 
  firstName: 'Max',
  lastName: 'Muster',
  fullName: function() { return this.firstName + ' ' + this.lastName }
}

user.fullName() // => 'Max Muster'

In ES6 we can define a function property using the following shorthand syntax:

let user = { 
  firstName: 'Max',
  lastName: 'Muster',
  fullName() { return this.firstName + ' ' + this.lastName }
}

user.fullName() // => 'Max Muster'

We can also define a gette...

nvm: Setting a default Node.js version

To set a default Node version for new shells, use nvm alias default <VERSION>:

nvm alias default 1.2.3

I like to use the most recent LTS version as my default:

nvm alias default lts/erbium

Rails Partials

Rails partials have a lot of "hidden" features and this card describes some non-obvious usages of Rails Partials.

Rendering a basic partial

The most basic way to render a partial:

render partial: 'partial' 

This will render a _partial.html.erb file. Notice how all partials need to be prefixed with _.

It's possible to define local variables that are only defined in the partial template.

# _weather.html.erb
<h1>The weather is <%= condition %></h1>

# index.html.erb
render partial: 'weather', locals: { condition: ...

Rubocop: Fix Style/SpecialGlobalVars

tl;dr

Don't forget require 'English' if you use a named global such as $LAST_MATCH_INFO. Otherwise this could result in an annoying bug.

Background

The code snippet of How to fix gsub on SafeBuffer objects was adjusted during a rubocop upgrade.

Rubocop tells you everything you need to know to fix the offense Style/SpecialGlobalVars:

Style/SpecialGlobalVars: Prefer $LAST_MATCH_INFO from the stdlib 'English' module (don't forget to...

Heads up: Deployment with newly generated SSH key (using ED25519) might fail

If you use a newer SSH key generated with the ED25519 algorithm instead of RSA (see Create a new SSH key pair), the deployment with Capistrano may fail with the following message:

The deploy has failed with an error: unsupported key type `ssh-ed25519'
net-ssh requires the following gems for ed25519 support:
 * ed25519 (>= 1.2, < 2.0)
 * bcrypt_pbkdf (>= 1.0, < 2.0)
See https://github.com/net-ssh/net-ssh/issues/565 for more information
Gem::LoadError : "ed25519 i...

Linux: Open a file with the default application

If you are on a Linux shell and want to open a file with whatever default application is configured for that type, this often works:

xdg-open Quote.odt
xdg-open invoice.pdf
xdg-open index.html

Make an alias so you have a simpler API (like Mac OS): alias open=xdg-open.

Manipulate color with Sass functions

Sass comes with many built-in functions to manipulate color. Some of the more interesting functions include:

adjust-hue($color, $degrees)
Changes the hue of a color.

lighten($color, $amount)
Makes a color lighter.

darken($color, $amount)
Makes a color darker.

saturate($color, $amount)
Makes a color more saturated.

desaturate($color, $amount)
Makes a color less saturated.

grayscale($color)
Converts a color to grayscale.

complement($color)
Returns the compleme...

Jasmine: Testing AJAX calls that manipulate the DOM

Here is a Javascript function reloadUsers() that fetches a HTML snippet from the server using AJAX and replaces the current .users container in the DOM:

window.reloadUsers = ->
  $.get('/users').then (html) ->
    $('.users').html(html)

Testing this simple function poses a number of challenges:

  • It only works if there is a <div class="users">...</div> container in the current DOM. Obviously the Jasmine spec runner has no such container.
  • The code requests /users and we want to prevent network interaction in our uni...

Rails: Using database default values for boolean attributes

In the past we validate and set default values for boolean attributes in Rails and not the database itself.

Reasons for this:

  • Older Rails didn't support database defaults when creating new records
  • Application logic is "hidden" in the database

An alternative approach, which currently reflects more the general opinion of the Rails upstream on constraints in the database, is adding default values in the schema of the database itself. We also ...

HTTP headers can only transport US-ASCII characters safely

HTTP header values must only contain low-ASCII (7-bit) characters for safe transport. From RFC 7230:

Historically, HTTP has allowed field content with text in the ISO-8859-1 charset [ISO-8859-1], supporting other charsets only through use of [RFC2047] encoding. In practice, most HTTP header field values use only a subset of the US-ASCII charset [USASCII]. Newly defined header fields SHOULD limit their field values to US-ASCII octets.

If you need to transport 8-bit+ characters (e.g...

Unpoly 2.7.2 released

This is a maintenance release to bridge the time until Unpoly 3 is completed. This release includes the following changes:

  • When pushing a history state, don't mutate the previous history state.
  • Fix a bug where the [up-animation] attribute could not be used to control a new overlay's opening animation.
  • The NPM package is now 800KB smaller.

This is the last release with support for Internet Explorer 11. Future releases will support Chrome, Firefox, Edge and the last two majors of Sa...

Configuring RubyGems to not install documentation by default

When installing gems, a lot of time is spent building locally installed documentation that you probably never use.

We recommend you disable documentation generation for gem install by default.
Note that Bundler won't install documentation, so this advice applies only when installing gems manually.

If you don't already have it, create a ~/.gemrc file. The gemrc is a Yaml file, so add the following line to add default switches to the gem command.

gem: --no-document

(If you do n...

count vs. size vs. length on ActiveRecord associations

TLDR

  • When counting records in an association, you should use #size in most cases.
  • It will not work if the parent record has never been saved. Also there are finer distinctions between #size and #count. See below.

count

  • Always makes a COUNT(*) query if a counter cache is not set up.
  • If a counter cache is set up on the association, #count will return that cached value instead of executing a new query.

size, if the association has already been loaded

  • Counts elements in the already loaded array.
  • Does not ...

HTTP Client in RubyMine

RubyMine has a HTTP Client that can be useful to test web APIs.
Just create a .http scratch file an write your request in it.
The request can then be executed with the "Run all requests in File" button above the file.

Some alternatives:

The format for request is like this:

Method Request-URI HTTP-Version
Header-field: Heade...