How to bind an event listener only once with Unpoly

You can use Unpoly's up.on with a named listener function and immediately unbind this event listener with { once: true }:

up.on('up:fragment:inserted', { once: true }, function () { ... })

In Unpoly 1 you can immediately unregister the listener with up.off:

up.on('up:fragment:inserted', function fragmentInsertedCallback() {
  up.off('up:fragment:inserted', fragmentInsertedCallback)
  // ... code for the callback function, which should run only once
})

Exam...

JavaScript: Working with Query Parameters

tl;dr: Use the URLSearchParams API to make your live easier if you want to get or manipulate query parameters (URL parameters).

URLSearchParams API

The URLSearchParams API is supported in all major browsers except IE 11.

It offers you a bunch of useful methods:

  • URLSearchParams.append() - appends a query parameter
  • URLSearchParams.delete() - deletes the specified query parameter
  • URLSearchParams.get() - returns the value of the specified query parameter
  • `URLSearchP...

Version 5 of the Ruby Redis gem removes Redis.current

Redis.current will be removed without replacement in redis-rb 5.0.
Version 4.6.0 adds deprecation warnings for Redis.current and Redis.current=:

`Redis.current=` is deprecated and will be removed in 5.0.

If your application still uses Redis.current, you can only fix it by no longer using it. Here is how.

Redis.new when you need it

You can easily instantiate a Redis client when you need it.

There is probably already a constant like REDIS_URL that you use to configure Sidekiq or similar. So just use that one.

``...

RSpec: You can super into parent "let" definitions

RSpec's let allows you to super into "outside" definitions, in parent contexts.

Example:

describe '#save' do
  subject { described_class.new(attributes) }
  let(:attributes) { title: 'Example', user: create(:user) }

  it 'saves' do
    expect(subject.save).to eq(true)
  end

  context 'when trying to set a disallowed title' do
    let(:attributes) { super().merge(title: 'Hello') } # <==

    it 'will not save' do
      expect(subject.save).to eq(false)
    end
  end
end

I suggest you don't make a habit of using this regula...

PostgreSQL: "WHERE NOT <column> = '<value>'" statements do not include NULL values

Sometimes we write plain SQL queries in migrations so we don't have to mock ActiveRecord classes. These two migrations do the same:

class Migration1 < ActiveRecord::Migration[5.2]
  class User < ActiveRecord::Base; end

  def up
    add_column :users, :trashed, :boolean
    
    User.update_all(trashed: false)
  end
end

class Migration2 < ActiveRecord::Migration[5.2]
  def up
    add_column :users, :trashed, :boolean

    update("UPDATE users SET trashed = #{quoted_false}")
  end
end

The plain SQL migration is less code, but h...

Rails 6.1: where.not changes behaviour from NOR to NAND

Since Rails 6.1, if we use where.not with multiple attributes, it applies logical NAND (NOT(A) OR NOT(B)) instead of NOR (NOT(A) AND NOT(B)). If you do not take care, this change will increase the matched set.

Examples

"Don't send newsletters neither to admins nor to trashed users!" becomes "Don't send newsletters to trashed admins".

User.where.not(role: 'admin', trashed: true)
# Before Rails 6.1, with NOR
=> "SELECT "users".* FROM "users" WHERE "users"."role" != 'admin' AND "users"."trashed" != TRUE"
# Equivale...

Nokogiri: How to parse large XML files with a SAX parser

In my case [...] the catalog is an XML that contains all kinds of possible products, categories and vendors and it is updated once a month. When you read this file with the Nokogiri default (DOM) parser, it creates a tree structure with all branches and leaves. It allows you to easily navigate through it via css/xpath selectors.

The only problem is that if you read the whole file into memory, it takes a significant amount of RAM. It is really ineffective to pay for a server if you need this RAM once a month. Since I don't need to n...

Caching in Rails < 6.1 may down parts of your application when using public cache control

TL;DR When using Cache-Control on a Rails application, make sure the Vary: Accept header is set.

Proxy caching is a good feature to serve your publicly visible application content faster and reduce load on your servers. It is e.g. available in nginx, but also affects proxies delivered by ISPs.

Unfortunately, there is a little problem in Rails < 6.1 when delivering responses for different MIME-types. Say you have an arbitrary route in your Rails application that is able to respond with regular HTML and JSON. By sending the specific ...

Spreewald 4.3.3 released

Field error steps

Spreewald's The ... field should have an error and The ... field should have the error ... steps now have built-in support for Rails and Bootstrap (v3-v5) error classes. When using Bootstrap, it is no longer necessary to overwrite the steps in your project.

At the same time, support for formtastic has been removed as there were no real use cases. Due to that, no breaking change was introduced, as the amount of users affected by this should be zero (it was neither in the documentation nor tested).

Users may now add...

The TCF 2.0 (Tranparency and Consent Framework) standard, and what you should know about it

The Interactive Advertising Bureau (IAB) is a European marketing association which has introduced a standard how advertising can be served to users in line with the General Data Protection Regulation (GDPR). This standard is called the TCF 2.0 (Transparency and Consent Framework). If you want to integrate any kind of advertising into a website, chances are the advertising network will require your website to implement that standard. This is a very brief overview of what this means:

The basic idea in the TCF 2.0 ...

Strict Loading Associations can prevent n+1 queries

Rails 6.1 has a "strict loading" mode that forces the developer to preload any association they plan to use. Associations no longer load lazily. An error is raised when reading an association that was not preloaded.

Enabling strict loading is a tool to prevent n+1 queries.

Strict loading can be enabled for individual records, for a single association,...

Using feature flags to stabilize flaky E2E tests

A flaky test is a test that is often green, but sometimes red. It may only fail on some PCs, or only when the entire test suite is run.

There are many causes for flaky tests. This card focuses on a specific class of feature with heavy side effects, mostly on on the UI. Features like the following can amplify your flakiness issues by unexpectedly changing elements, causing excessive requests or other timing issues:

  • Lazy loading images
  • Autocomplete in search f...

RSpec: automatic creation of VCR cassettes

This RailsCast demonstrated a very convenient method to activate VCR for a spec by simply tagging it with :vcr.

For RSpec3 the code looks almost the same with a few minor changes. If you have the vcr and webmock gems installed, simply include:

# spec/support/vcr.rb
VCR.configure do |c|
  c.cassette_library_dir = Rails.root.join("spec", "vcr")
  c.hook_into :webmock
end

RSpec.configure do |c|
  c.around(:each, :vcr) do |example|
    name = example.metadata[:full_descripti...

Better numeric inputs in desktop browsers

You want to use <input type="number"> fields in your applications.
However, your desktop users may encounter some weird quirks:

  1. Aside from allowing only digits and decimal separators, an "e" is also allowed (to allow scientific notation like "1e3").
    • Non-technical users will be confused by this.
    • Your server needs to understand that syntax. If it converts only digits (e.g. to_i in Ruby) you'll end up with wrong values (like 1 instead o...

Event delegation (without jQuery)

Event delegation is a pattern where a container element has a single event listener that handles events for all descendants that match a CSS selector.

This pattern was popularized by jQuery that lets you do this:

$('.container').on('click', '.message', function(event) {
  console.log("A message element was clicked!")
})

This technique has some advantages:

  1. When you have many descendants, you save time by only registering a single listener.
  2. When the descendants are changed dynamic...

Capybara can find links and fields by their [aria-label]

Sometimes a link or input field has no visible label. E.g. a text field with a magnifying glass icon 🔎 and a "Search" button does not really need a visible label "Query".

For accessibility reasons it is good practice to give such a field an [aria-label] attribute:

<input type="search" aria-label="Search contacts">

This way, when a visually impaired user focuses the field, the screen reader will speak the label text ("Search contacts").

Info

Without an `[aria-...

Git shortcut to fixup a recent commit

git --fixup is very handy to amend a change to a previous commit. You can then autosquash your commits with git rebase -i --autosquash and git will do the magic for you and bring them in the right order. However, as git --fixup wants a ref to another commit, it is quite annoying to use since you always have to look up the sha of the commit you want to amend first.

Inspired by the [shortcut to checkout recent branches with fzf](https://makandracards.com/makandra/505126-g...

Rails: Removing the cucumber-rails warning when setting cache_classes to false without Spring enabled

We are using Spring in our tests for sequential test execution but not for parallel test execution. And Rails requires you to set the config.cache_classes = false if you are using Spring in tests.

With our setup, this would raise the following error in cucumber-rails for parallel test executions due to some legacy database cleaner issue.

WARNING: You have set Rails' config.cache_classes to false
    (Spring needs cache_classes set to false). This is known to cause probl...

You should probably load your JavaScript with <script defer>

It is generally discouraged to load your JavaScript by a <script src> tag in the <head>:

<head>
  <script src="app.js"></script>
</head>

The reason is that a <script src> tag will pause the DOM parser until the script has loaded and executed. This will delay the browser's first contentful paint.

A much better default is to load your scripts with a <script src defer> tag:

<head>
  <script src="app.js" defer></script>
</head>

A deferred script has many useful properties:

  • I...

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

NVM: How to automatically switch version when changing directories

The Node Version Manager allows installing multiple NodeJS versions and switching between them.
By default, it does not automatically switch versions when entering a directory that holds a .nvmrc file.

The project's readme document offers a bash function which calls nvm use after each cd. In fact, it replaces cd in your bash.

I did not want to do that, but instead use the $PROMPT_COMMAND feature. So here is my take on it.
Note that it is much shorter, it probably does a f...

Heads up: counting may be slow in PostgreSQL

The linked article points out that COUNT queries might be unexpectedly slow in PostgreSQL.

If you just need to know "are there any records" use any?. This uses SELECT 1 AS one FROM ... LIMIT 1 under the hood.
If you just need to know "are there no records" use empty? or none?. This uses SELECT 1 AS one FROM ... LIMIT 1 under the hood.

In short: Replace foo.count > 0 with foo.any? or foo.count == 0 with foo.none?

If you require quick counts and can tolerate some level of imprecision, consider exploring the ...

Accessing JavaScript objects from Capybara/Selenium

When testing JavaScript functionality in Selenium (E2E), you may need to access a class or function inside of a evaluate_script block in one of your steps. Capybara may only access definitions that are attached to the browser (over the window object that acts as the base). That means that once you are exporting your definition(s) in Webpacker, these won't be available in your tests (and neither in the dev console). The following principles/concepts also apply to Sprockets.

Say we have a StreetMap class:

// street_map.js
class S...