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 }, duration: 10.seconds)
end

The problem

# This doesn't actually test concurrency control
test('enqueues both jobs') do
  MembershipJob.perform_later(membership)
  MembershipJob.perform_later(membership)
  
  assert_enqueued_jobs(2, only: MembershipJob)
  # Both...

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

pnpm: How to update a single package conservatively

I recently had to update a few selective npm libraries in a project that uses pnpm to apply a CVE mitigation. My first instinct was to modify the package.json file and hope that pnpm install only makes the most minimal changes. But that's not always the case, and there is a much better way.

Use pnpm up (aliased to update and upgrade) with a set of exact library names and versions. The resulting changes (both to the package.json and pnpm lockfile) will be minimal. Example for my CVE-2025-66478 fix:

pn...

Project management best practices: Standup

If the project team consists of at least 2 members, do a daily standup. It should not take much longer than 15 minutes.

Format

Tell everyone else

  • what you did yesterday
  • what you intend to do today
  • where you might need help or other input
  • if there are new developments everyone needs to know about

A "still working on X, will probably be done today" is totally fine. No need to tell a long story.

If you are out of work, find a new story with the others.

If there are new stories in the backlog, look at them and

  • make sure ev...

Rails disables CSRF protection in tests

The default configuration of Rails disables CSRF protection in tests. If you accidentally forget to send the CSRF token for POST requests, your tests will be green even though your application is broken.

You probably want to enable CSRF protection in tests that can speak JavaScript.

For RSpec...

How to iterate over all ActiveRecord models

Sometimes you have a maintenance script where you want to iterate over all ActiveRecord models. Rails provides this out of the box:

# script/maintenance_task.rb

# Load all models eagerly, otherwise you might only get a subset
Rails.application.eager_load!

ApplicationRecord.descendants.select(&:table_exists?).each do |model|
  # ...
end

Caution

If you iterate over individual records, please provide a progress indicator: See [https://makandracards.com/makandra/625369-upload-run-scripts-production](https://makandracards.com/...

Rails: Join model table migration template

When creating a database table for a join model without further importance, you can use Rails' create_join_table:

class CreateSchoolsStudents < ActiveRecord::Migration[7.2]
  def change
    create_join_table :schools, :students, column_options: { foreign_key: true } do |t|
      # t.timestamps # Optional
      t.index [:student_id, :school_id], unique: true
    end
  end
end

This will create a table without an id column and without timestamps. It will have school_id and student_id columns with null: false constraints ...

Plain CSS does not support variables in media queries (yet)

It's not possible to use variables in media queries with plain CSS.

@media (max-width: var(--some-pixel-size)) { ... } /* Does not work */

Postcss Plugin

If you're using PostCSS to postprocess your CSS, you can configure postcss-custom-media and add this feature:

@custom-media --small-variable-name(max-width: 968px);

@media (--small-variable-name) { ... } /* works */