We now have our own memoization gem "Memoized"

We forked trusty memoizer to make two changes:

  1. Memoized methods now preserve their arity. Previously all memoized methods had an arity of -1.
  2. Memoized methods are now faster at runtime. This will only be noticable if you call a memoized methods many times in the same request.

We published our fork as a new gem named memoized.

memoized is API-compatible to memoizer, you just need to include Memoized instead of `M...

Balance your texts today with text-wrap: balance

So you have a heading that is just barely wider than the container it should fit into, and it wraps a single word to a new line and it's not really pretty?
Cry no more, for you can use text-wrap: balance today to fix that. At least in some browsers.

When browsers encounter a text-wrapping element with text-wrap: balance style, they will try breaking to a new line sooner, if it balances out the width of lines.

Without text-wrap: balance With text-wrap: balance
Image ![...

Checklist for Implementing Design

We have a long-standing checklist for merge requests. However, it hardly matches the intricate requirements for design. This checklist fills the gap.

Before starting implementing, look at all designs: are there components similar to yours? Have they already been implemented? Can you build on this prior art when implementing yours?

Checklist: I confirm my design implementation

  • has been tested manually by me
  • adheres to the code style of the project (e.g. BEM)
  • avoids "magic numbers" (don't say e.g. ...

Git: Splitting up changes into several commits

Splitting up commits makes the process of reviewing often easier, since you can create several merge requests or review every commit one by one.

So when you find out that you have portions of the code that you initially didn't intend to change or when you do some refactoring along the current changes, you can use one of the following processes to split up the changes into several commits in a logical order:

#1 Splitting up the last n commits into m commits
#2 Adding changes to a previous commit
2.1 While adding new changes
2.2 S...

Best practice: How to manage versions in a package.json

It most cases it's not necessary to add a version constraint next to your packages in the package.json. Since all versions are saved in a lockfile, everyone running yarn install will get exactly the same versions. Yarn saves this lockfile as yarn.lock and npm as package-lock.json.

There are some exceptions, where you can consider adding a version constrain to the package.json:

  • You are not checking in lockfile the into the version control (not recommended)
  • A specific package has a bug in a more recent version
  • You want to en...

Best practice: How to manage versions in a Gemfile

It most cases it's not necessary to add a version constraint next to your gems in the Gemfile. Since all versions are saved in the Gemfile.lock, everyone running bundle install will get exactly the same versions.

There are some exceptions, where you can consider adding a version constrain to the Gemfile:

  • You are not checking in the Gemfile.lock into the version control (not recommended)
  • A specific gem has a bug in a more recent version (adding a comment for the reason is highly recommended)
  • You want to ensure no one upgrade...

RSpec 3 argument constraints use weak equality

If you expect method calls in RSpec 3, be aware that the argument matchers use very liberal equality rules (more like === instead of ==).

For example:

expect(subject).to receive(:foo).with(MyClass)

subject.foo(MyClass)      # satisfies the expectation
subject.foo(MyClass.new)  # also satisfies the expectation

expect(subject).to receive(:bar).with(/regex/)

subject.bar(/regex/)      # satisfies the expectation
subject.bar('regex')      # also satisfies the expectation

This is usually not an issue, except when your method ...

Rails < 5: How to get after_commit callbacks fired in tests

If you use transactional_fixtures or the database_cleaner gem with strategy :transaction, after_commit callbacks will not be fired in your tests.

Rails 5+

Rails 5 has a fix for this issue and no further action is needed.

Rails 3, Rails 4

Add the gem test_after_commit to your test group in the Gemfile and you are done. You don't need to change the database strategy to deletion (wh...

ActiveRecord: Creating many records works faster in a transaction

When you need to insert many records into the same table, performance may become an issue.

What you can do to save time is to open a transaction and save multiple records within that transaction:

transaction do
  500.times { Model.create! }
end

Although you will still trigger 500 INSERT statements, they will complete considerably faster.

When I tried it out with a simple model and 500 iterations, the loop completed in 1.5 seconds vs. 6 seconds without a transaction.

Alternative

Another fast way to insert many ...

Local deployment after pipeline succeeds

If you have a fully functional CI pipeline but no CD, you might find yourself frequently waiting for CI (with "merge after pipeline succeeds") just to perform the deployment.

The following command waits for the next commit that lands on the current branch (should be main or similar) and proceeds to deploy staging afterwards:

alias await-deployment='watch -g git pull && bundle exec cap staging deploy'

Note

Use at your own risk.
You could be deploying code from someone else that was pushed to the same branch in the meantime.

How to configure case insensitive git output

Git commands like diff use the less binary for their output representation.

I often find myself searching for strings like todo, then switching to the case-insensitive mode (-i) and re-doing my search.
Today I figured out that you can configure git to show case insensitive diffs every time:

git config --global core.pager 'less -i'

Vim: Simple way to edit several lines at once at the same cursor position

Within Vim do the following:

  • Move cursor to the first starting line where you want to start editing
  • ctrl + v to enter select mode to select all characters in one column
  • Move the cursor vertically down until you selected the last line
  • shift + i to got into "multiple" insert mode
  • Do all the required editings
  • Use the ESC-character exit insert mode
  • Press ESC-character to apply all changes

Hint

This does not work with deleting and editing at once

  • If you first want to delete the content, can also use the select mode ...

Linux: How to make a terminal window title reflect the current path

By default, your terminal emulator (Gnome Terminal, Terminator, etc.) sets some kind of window title to reflect the shell type you are running (e.g. /bin/bash).
This is most often not too helpful, but you can change that from your shell.

To set a specific title, print an escape sequence like this:

echo -en "\033]0;Hello\a"

You can easily include the current path:

echo -en "\033]0;$(pwd)\a"

Or, to replace your home directory's part with a tilde:

echo -en "\033]0;$(pwd | sed -e "s;^$HOME;~;")\a"

Or,...

Git diff: Deemphasizing code that was only moved around

In long diffs, it can become impossible to spot small changes in larger blocks of moved code. This may be either a method that was moved from the top to the bottom of a file, or a long test file that was split in many.

Fortunately, Git offers a special highlighting mode that directs the reader's attention to relevant code parts:

git diff --color-moved=dimmed-zebra

It will dim lines that were moved around without changes, and highlight changed lines.
To easily use dimmed-zebra mode, configure an alias:

# ~/.gitconfig
[alias]
 ...

Testing shared traits or modules without repeating yourself

When two classes implement the same behavior (methods, callbacks, etc.), you should extract that behavior into a trait or module. This card describes how to test that extracted behavior without repeating yourself.

Note that the examples below use Modularity traits to extract shared behavior. This is simply because we like to do it that way at makandra. The same techniques apply for modules and overriding self.included.

Example
---...

How to: Run bundle install in parallel

You can run bundle install in parallel. This might be helpful for development, where you often install many new gems when switching between projects.

  1. Find out the number of processors you have:
lscpu
  1. Set the config in your ~/.bundle/config globally (replace 8 with your number of proccessors):
bundle config jobs 8

Note

If you suspect parallel execution for bundling issues, you can try serially with bundle install --jobs 1.

netstat: How to show listening ports

Sometimes it's necessary for you to check which ports are in use on your local machine and which process is using it. To list this information you can use the following command (which is pretty easy to memorize for Germans 🌷):

sudo netstat -tulpn
  • t: tcp
  • u: udp
  • l: listening ports
  • p: process
  • n: network

Use sudo to see the name of the process.

Finding open ports in the netstat output

You should look for rows with State: LISTEN.

Rows for local address 127.0.0.1 or...

Raising JavaScript errors in Ruby E2E tests (RSpec, Cucumber)

A JavaScript error in an E2E test with Selenium will not cause your test to fail. This may cause you to miss errors in your frontend code.

Using the BrowserConsole helper below you can check your browser's error console from your E2E tests.

The following will raise BrowserConsole::ErrorsPresent if there is an error on the browser console:

BrowserConsole.assert_no_errors!

Ignoring errors

You can ignore errors by their exact message:

BrowserConsole.ignore('Browser is burning')

You can ignore errors with me...