CSS: Don't target multiple vendor-prefixed pseudo-elements in a single rule

Some pseudo-elements need to be addressed with vendor prefixes. E.g. ::selection is not supported by Firefox, you need to use ::-moz-selection instead.

What you cannot do is to define a single CSS rule to address both the standard and vendor-prefixed form:

::selection, ::-moz-selection {
  background-color: red;
}

This rule will be ignored by all browsers. If a browser does not know al...

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

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

Knapsack: Rerun a flaky test locally

Knapsack allows you to rerun a specific job locally. This is helpful to run specs in the exactly same order like in the CI.

Example for running rspec 3/8 with a seed output of 20689:

CI_NODE_INDEX=2 CI_NODE_TOTAL=8 bundle exec rake "knapsack:rspec[--seed=20689]"

*Note: the environment variable ...

Beware: Many browsers define window.event

Some browsers define window.event, which will return a copy of the "current" event. However, this is not defined by the W3C. Most importantly, Firefox does not support it, neither do recent versions of IE.

You should completely avoid accessing the global event and instead pass the event object around that the event handler receives. The easiest protection against accidentally accessing window.event is just never naming the event event, but e or evnt or so.

function brokenInFirefox() {
  event.preventDefault() // Brea...

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 (optionally setting the previous author manually)
  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
    

    ...

How to explain SQL statements via ActiveRecord

ActiveRecord offers an explain method similar to using EXPLAIN SQL statements on the database.

However, this approach will explain all queries for the given scope which may include joins or includes.

Output will resemble your database's EXPLAIN style. For example, it looks like this on MySQL:

User.where(id: 1).includes(:articles).explain
EXPLAIN for: SELECT `users`.* FROM `users`  WHERE `users`.`id` = 1
+----+-------------+-------+-------+---------------+
| id | select_type | table | type  | possible_keys |
+----+-----...

Always disable autocomplete for date pickers

When we write a form with date fields, we often use graphical data picker like Rome to get a consistent calendar popup on all browsers.

When you integrate a date picker popup, remember to also set autocomplete="off" on the text input that opens the calendar on click. Otherwise the autocomplete suggestions will cover the calendar box and make it unusable:

Image

If you are using a tool like Unpoly you might want to set autocomplete="off" i...

Cancelling event propagation

Within an event handler, there are multiple methods to cancel event propagation, each with different semantics.

  • event.preventDefault()

    Only prevents the default browser behavior for the click, i.e. going to a different url or submitting a form.

    When invoked on a touchstart event, this also prevents mouse events like click to be triggered.

  • event.stopPropagation()

    Prevents the event from bubbling up the DOM.

  • `event.st...

Controlling how your website appears on social media feeds

When a user shares your content, a snippet with title, image, link and description appears in her timeline. By default social networks will use the window title, the first image, the current URL and some random text snippet for this purpose. This is often not what you want.

Luckily Facebook, Twitter, etc. lets you control how your content appears in the activity streams. They even have agreed on a common format to do this: OpenGraph <meta> tags that go into your HTML's <head>:

<meta property="og:url" content="http://start.m...

How to bulk-unwatch many repositories on Github

To easily opt out of notifications for a large number of Github repositories, go to https://github.com/watching.

Defining custom RSpec matchers

There are three ways to define your own RSpec matchers, with increasing complexibility and options:

1) Use RSpec::Matchers.define

RSpec::Matchers.define :be_a_multiple_of do |expected|
  match do |actual|
    actual % expected == 0
  end
  
  # optional
  failure_message do |actual|
    "expected that #{actual} would be a multiple of #{expected}"
  end
  
  # optional
  failure_message_when_negated do |actual|
    "expected that #{actual} would not be a multiple of #{expected}"
  end
end
  • This is automatically available i...

Your database tables should always have timestamps

Whenever you create a table from a database migration, remember to add updated_at and created_at timestamps to that table. Without those timestamps, investigating future bug reports will be hell. Always have timestamps.

Adding timestamps to new tables

When you create a table using create_table, you can add timestamps by using the timestamps shortcut:

class CreateEpisode < ActiveRecord::Migration
  def change
    create_table :episodes do |t|
      t.string :name
      t.timestam...

Rubocop fails with undefined StringIO

If your rubocop run fails with a stack like

rubocop-1.61.0/lib/rubocop/server/socket_reader.rb:36:in `ensure in read!': undefined method `string' for nil:NilClass (NoMethodError)
        Cache.stderr_path.write(stderr.string)
                                      ^^^^^^^
...
rubocop-1.61.0/lib/rubocop/server/socket_reader.rb:27:in `read!': uninitialized constant RuboCop::Server::SocketReader::StringIO (NameError)

        stderr = StringIO.new
                 ^^^^^^^^

this card might help you.

In old versions of rubocop stringio w...

Controlling the order of DOM event listeners

Event listeners are called in the order of their registration:

button.addEventListener('click', () => console.log("I run first"))
button.addEventListener('click', () => console.log("I run second"))

Sometimes you want a listener to always run first (or last), but have no control over the order in which other listeners are registered.
There is no clean mechanism in the DOM API for this. This card shows some hacks to do it anyway.

Exploiting the capturing phase

Before an event bubbles up from an element to the document, it...

How to accept more than 4k query parameters in Rails

I have a form with a dynamic number of fields. Submitting it worked fine until I tried out a very large version of it. The development log was not very helpful:

Invalid or incomplete POST params

As it turned out, the following exception did not reach the log output

Rack::QueryParser::QueryLimitError
Error Message: total number of query parameters (6313) exceeds limit (4096)

If you ever happen to be in the same position, this is how to increase the limit of allowed query parameters:

# config/initializers/rack_query_parser.rb
...

Testing ActiveJob `limits_concurrency` with Solid Queue

The :test adapter doesn't respect limits_concurrency configuration. Switch to :solid_queue adapter in your test to verify blocking behavior.

Job Configuration

class MembershipJob < ApplicationJob
  limits_concurrency(key: ->(membership) { membership })
end

The problem

When using the default test mode for enqueuing jobs, both will be enqueued immediately. However, we actually we want to test that only one of both will be enqueued as the other should have been blocked.

# This doesn't actually test concurren...

Generating test images on the fly via JavaScript or Ruby

When you need test images, instead of using services like lorempixel or placehold.it you may generate test images yourself.

Here we build a simple SVG image and wrap it into a data: URI. All browsers support SVG, and you can easily adjust it yourself.
Simply set it as an image's src attribute.

JavaScript

Simple solution in modern JavaScript, e.g. for use in the client's browser:

function svgUri(text) {
  let svg = `
    <svg wid...

Use a global .gitignore file to ignore stuff from your machine

Sometimes you want git to ignore certain files that appear on your machine. You can do this in 3 ways:

  • Per project, in the project's .gitignore file
  • Per project, in a local exclude file
  • Globally on your machine

Downsides of per-project .gitignore entries

While it might be tempting to set it per project (other devs might benefit from it), you

  • need to do it each time for every project
  • "pollute" a project's .gitignore file with stuff...

Faux-disabled fields in HTML forms

You want to prevent input to a form field, but all the solutions have side effects:

  • The [readonly] attribute is only available for text fields, but not for checkboxes, selects, buttons, etc.
  • The [disabled] attribute is available for all kinds of fields, but will no longer include the field value in the submitted form data.
  • pointer-events: none still allows keyboard input, and does not indicate disabledness visually, or to screen readers.

Ye...

Updated: Learn how to use ruby/debug

Added a section about remote debugging.

Opt out of selenium manager's telemetry

If you use the selenium-webdriver gem, it will sneakily phone home once every hour whenever you run a browser based feature spec.

Check if you're affected

Check if ~/.cache/selenium/se-metadata.json exists. (It contains a "ttl" timestamp of its last/next anaytics call. You can parse it with Ruby's Time.at.)

Opt out

You can opt out either globally:

# .bashrc
export SE_AVOID_STATS=true

or project based

# spec_helper...

Cucumber CI job quirks

Most of our CI pipelines don't use the --retry flag for Cucumber and instead build their own retry via the tmp/failing_features.txt file.

Benefits:

  • It's possible to only use -f pretty for the rerun.

Drawbacks:

  • MAJOR: With our current setup, when the main run fails without writing a tmp/failing_features.txt (e.g. due to a syntax error), the CI job will pass
  • MINOR: With our current setup, we lose the test coverage of the main run

A fix for the passing CI despite syntax error could look like this:

cucumber:
  # ...
  sc...

Debugging Rails Active Jobs with the Vanilla Adapters

Short reference on how to quickly debug the vanilla Rails job adapters.

Queue Adapters by Environment

Environment Adapter Jobs Run In Worker Needed?
development :async Rails server process No
test :test Not executed (stored) No
production :solid_queue Separate worker Yes (bin/jobs)

Development (:async)

Jobs run in background threads ([Concurrent Ruby ThreadPoolExecutor](https://ruby-concurrency.github.io/concurrent-ruby/maste...