Your browser might silently change setTimeout(f, 0) to setTimeout(f, 4)

When you're nesting setTimeout(f, 0) calls, your browser will silently increase the delay to 5 milliseconds after the fourth level of nesting.

This is called "timeout clamping" and defined in the HTML spec:

If nesting level is greater than 5, and timeout is less than 4, then set timeout to 4.

Timeouts are clamped harder in background tabs

On a similar note, all major browsers have implemented throttling rules for setInterval and setTimeout calls from tabs...

How to speed up JSON rendering with Rails

I was recently asked to optimize the response time of a notoriously slow JSON API endpoint that was backed by a Rails application.
While every existing app will have different performance bottlenecks and optimizing them is a rabbit hole of arbitrary depth, I'd like to demonstrate a few techniques which could help reaching actual improvements.

The baseline

The data flow examined in this card are based on an example barebone rails app, which can be used to reproduce the r...

RubyMine: Adjust Code Templates

tl;dr

To adjust code templates in RubyMine, navigate to Settings -> Editor -> File and Code Templates.

Example

You can navigate to the test file of the currently open file with the shortcut Ctrl + T. If no test file exists, you can generate a new test file. If you are not pleased with the output, you can adjust the related code template. To do this, open the project settings and navigate to Editor -> File and Code Templates -> Files. Now, choose your relevant file type and adjust the code template according ...

Unpoly 3.9.0 released

Unpoly enhances your HTML with new attributes to build dynamic UI on the server. It works with any language and gracefully degrades without JavaScript.

The 3.9.0 release brings many fixes and quality-of-life improvements that were requested by the community. The vast majority of these changes are backward compatible. One breaking change can be found with making links followable. Existing usage is polyfilled by [`unpoly-migr...

Protected and Private Methods in Ruby

In Ruby, the meaning of protected and private is different from other languages like Java. (They don't hide methods from inheriting classes.)

private

Private methods can only be called with implicit receiver. As soon as you specify a receiver, let it only be self, your call will be rejected.

class A
  def implicit
    private_method
  end
  
  def explicit
    self.private_method
  end
  
  private
  
  def private_method
    "Private called"
  end
end

A.new.implicit
# => "Private called"

A.new.explicit
# => NoMethod...

Advisory: Excel converts CSV entries to formulas

If your application exports CSV, be advised that Excel and other spreadsheet applications treat certain cells (those starting with =, +, - or @) as formulas.

This is an issue if you output user input. Not only is it probably not what you want, it also poses a security risk. See the link for attack vectors.

Note that current Excel versions will warn the user when opening the file. At least for the code execution vulnerability, these three warnings seems adequate to me.

Code execution warnings:

![Image](/makandra/47624/attach...

How to: Ensure proper iconfont rendering with Webpack

Background

After switching a project from Sprockets to Webpack, I started observing a bug that was hard to debug: Our custom icon font could sometimes not be displayed until a full page reload.

Digging deeper the only difference before and after the page load was the encoding interpretation of the iconfont stylesheet:

Correct representation (UTF-8):

.icon:before {
    content: ""
}

Broken representation (other charset):
`...

How to query GraphQL APIs with Ruby

While most Rails Apps are tied to at least one external REST API, machine-to-machine communication via GraphQL is less commonly seen. In this card, I'd like to give a quick intro on how to query a given GraphQL API - without adding any additional library to your existing app.

Core aspects of GraphQL

Interacting with GraphQL feels a bit like querying a local database. You are submitting queries to fetch data in a given structure (like SELECT in SQL) or mutations to alter the database (similar to POST/PUT/DELETE in REST). You can ...

Rails npm packages will use an uncommon versioning scheme

When Rails releases a new version of their gems, they also release a number of npm packages
like @rails/activestorage or @rails/actioncable.

Unfortunately Rails uses up to 4 digits for their gem version, while npm only allows 3 digits and a pre-release suffix.

To map gem versions and npm versions, Rails is going to use a naming scheme like this:

Gem version npm version
7.0.0 7.0.0
7.0.1 7.0.100
...

JavaScript: Humanizing durations

Modern JavaScript includes Intl.NumberFormat to format numbers in different formats and locales.
In this card, we describe a wrapper for it that humanizes a given number of seconds in the "next best" unit, like seconds, minutes, etc.

Example usage

>> new Duration(42).humanized()
=> '42 Sekunden'
>> new Duration(123456).humanized()
=> '1 Tag'
>> new Duration(123456).humanized('es')
=> '1 día'

Code

Here is the code ...

Use the Git stash without shooting yourself in the foot

The Git stash does not work like a one-slot clipboard and you might shoot yourself in the foot if you pretend otherwise.

In particular git stash apply does not remove the stashed changes from the stash. That means you will probably apply the wrong stash when you do git stash apply after a future stashing.

To keep your stash clean, you can use

git stash pop

instead.

Another way to look at it:

git stash pop 

is the same as

git stash apply && git stash drop

Notice: In case of a conflict git will not pop th...

Too many parallel test processes may amplify flaky tests

By default parallel_tests will spawn as many test processes as you have CPUs. If you have issues with flaky tests, reducing the number of parallel processes may help.

Important

Flaky test suites can and should be fixed. This card is only relevant if you need to run a flaky test suite that you cannot fix for some reason. If you have no issues...

Ruby: Retrieving and processing files via Selenium and JavaScript

This card shows an uncommon way to retrieve a file using selenium where JavaScript is used to return a binary data array to Ruby code.

The following code example retrieves a PDF but the approach also works for other file types.

require "selenium-webdriver"

selenium_driver = Selenium::WebDriver.for :chrome
selenium_driver.navigate.to('https://example.com')
link_to_pdf = 'https://blobs.example.com/random-pdf'

binary_data_array = selenium_driver.execute_script(<<-JS, link_to_pdf)
  const response = await fetch(arguments[0])

  if (!r...

Cheat Sheet for the modern DOM API

See the attached link for a useful overview of modern (and classic) DOM API methods, like matches, contains, append, cssText, etc.

You will still need to look up some documentation, e.g. on how to modify a ClassList, but it's still better than browsing interfaces and superclasses of Element on MDN without knowing what to look for.

When coming from jQuery, also see the card on JavaScript without jQuery. This card includes a link to [You Don't Need jQuery](https://github.com/nefe/You-Dont-Need-jQuery/blob/maste...

How to debug file system access in a Rails application

It might sometimes be useful to check whether your Rails application accesses the file system unnecessarily, for example if your file system access is slow because it goes over the network.

The culprit might be a library like carrierwave that checks file existence or modification times, whereas your application could determine all this from your database.

Introducing strace

One option it to use strace for this, which logs all system calls performed by a process.

To do this, start your rails server using something like

DISA...

How to push to Git without running CI on GitLab CI, GitHub Actions, or Travis CI

If a project ist configured to spawn CI runners for tests or deployment when pushing to the Repo, a habit of pushing WIP commits regularly may conflict with that.
Here are two solutions that allow you to keep pushing whenever you feel like it.

Special commit message

To skip a CI run, simply add [ci skip] or [skip ci] to your commit message. Example:

git commit -m "wip authentication [ci skip]"

Git push options (GitLab)

In addition to that, GitLab CI supports Git push options. Instead of changing your commit message, ...

Bundler: Enforce consistent platform versions

Some rubygems come in platform-specific versions (i.e. "x86_64-linux") in addition to the usual "ruby" platform. This is often is done for gems with native extensions that want to deliver precompiled binaries for ease of installation. However, there is an issue on some versions of Bundler (at least 2.3.x) that makes it inconsistent which versions of a gem will be installed.

Why this happens

On (very) old versions of Bundler, the Gemfile.lock could never indicate which version of a gem was installed, i.e. the Gemfile read `nokogiri (1....

Make Nokogiri use system libxml2

The nokogiri gem provides different packages for several platforms. Each platform-specific variant ships pre-built binaries of libxml2, e.g. x86_64-linux includes binaries for 64bit Linux on Intel/AMD. This significantly speeds up installation of the gem, as Nokogiri no longer needs to compile libxml2.

However, this also means that for each security issue with libxml2, Nokogiri maintainers have to update their pre-built binaries and release a new version of the gem. Then, you need to update and ...

How to force horizontal panel layout for Chrome

Chrome's developer tools automagically choose vertical or horizontal panel layout, based on their width. You can disable that magic.

In the developer tools, klick the cogwheel icon (or press F1 when focusing the dev tools) to open the settings overlay.
Under "Preferences", in the "Appearance" section, find the "Panel layout" option. Set it to your liking.

Alternatively, press Ctrl+Shift+P and search for "panel layout".

Wat?

Vertical means that the DOM tree is next to the styles/etc panel, like so:

![vertical layout example](https:/...

Capistrano: How to find out which version of your application is currently live

When deploying, Capistrano puts a REVISION file into your application's release directory. It contains the hash of the commit which was deployed.

If you want to know the currently deployed release, simply SSH to a server and view that file.

$ cat /var/www/my-project/current/REVISION
cf8734ece3938fc67262ad5e0d4336f820689307

Capistrano task

When your application is deployed to multiple servers, you probably want to see a result for all of them.
Here is a Capistrano task that checks all servers with the :app role.

Simple debounce in vanilla JavaScript

Debouncing a method call delays its execution until after a specified time has passed.
If it's called again before that time has passed, its execution is delayed again.

This technique is commonly used to improve performance when code would be run more often than it needs to.
One example for that are scroll event handlers in JavaScript: You want to react to a user scrolling, but it's enough to do that when they have stopped scrolling.

Here is a small JavaScript function that you can use for that:

function debounce(callback...

Upgrading RubyGems to the last compatible version

Running gem update --system will install the latest version of RubyGems. However the latest version might not be compatible with your current version of Ruby.

To install the latest version that is compatible with your Ruby:

  • Go to the version history and find the latest compatible version (any Ruby constraint can be found in the right sidebar)
  • Append that version to the update command. E.g. to install the latest version compatible with Ruby 2:
    gem update --system 3.4.22
    

...

Rails: Example on how to extract domain independent code from the `app/models` folder to the `lib/` folder

This cards describes an example with a Github Client on how to keep your Rails application more maintainable by extracting domain independent code from the app/models folder to the lib/ folder. The approach is applicable to arbitrary scenarios and not limited to API clients.

Example

Let's say we have a Rails application that synchronizes its users with the Github API:

.
└── app
    └── models
        ├── user
        │   ├── github_client.rb
        │   └── sychronizer.rb
        └── user.rb

In this example the app folder ...

Ruby: How to make your ruby library configurable

You might know a few examples, where you configure some library via a block. One example is the Rails configuration:

Rails.application.configure do |config|
  config.enable_reloading = false
end

This card describes a simple example on how to make your ruby library configurable.

Example

module FooClient
  class Client
    class_attribute :config

    def self.configure
      self.config ||= Configuration.new
      yield(config)
    end

    def test
      uri = URI.parse(FooClient::Client.config.endpoint)
      Net:...