Be careful when checking scopes for blankness

Today I stumbled across a pretty harmless-looking query in our application which turned out to be pretty harmful and caused huge memory usage as well as downing our passenger workers by letting requests take up to 60 seconds. We had a method that received a scope and then checked, if the scope parameter was blank? and aborted the method execution in this case.

def foo(scope)
  return if scope.blank?
  
  # Use scope, e.g.
  scope.find(...)
end

We then called this method with an all scope: foo(Media::Document::Base.all). *...

Rails route namespacing (in different flavors)

TL;DR There are three dimensions you can control when scoping routes:

scope module: 'module', path: 'path', as: 'as' do
  resources :examples, only: :index
end

→ Path Helpers: as_examples_path and as_examples_url
→ URLs: /path/examples
→ Controller module: Module::ExamplesController and views location: app/views/module/examples/

These options work with resources as well, e.g. resources :examples, path: 'demonstration'

namespace vs scope

The main difference between namespace and scope is:
...

ES6 imports are hoisted to the top

From Exploring ES6:

Module imports are hoisted (internally moved to the beginning of the current scope). Therefore, it doesn’t matter where you mention them in a module and the following code works without any problems:

foo();
import { foo } from 'my_module';

Footgun example

When you're not aware of import hoisting you may be surprised that your code runs in a different order than you see in the source file.

The example below is taken from the [...

How to examine an unknown Ruby object

When debugging your application, you will come across objects created by some gem or framework. You don't have the source code at hand, still need to inspect this object. Here are some tools to do so:

Relevant methods

@object.methods - Object.instance_methods returns a list of methods excluding methods inherited from Object. This makes the methods list drastically more relevant. You can also try subtracting other base classes like ActiveRecord::Base.methods etc.
To further narrow it down you can also just look at public methods...

How to display an unsaved changes alert

All browsers implement an event named beforeunload. It is fired when the active window is closed and can be used to display an alert to warn the user about unsaved changes.

To trigger the alert, you have to call preventDefault() on the event.

Note

The beforeunload event is only dispatched when the user navigation makes a full page load, or if it closes the tab entirely. It will not be dispatched when navigating via JavaScript. In this case you need to ...

Working on the Linux command line: How to bash `cd` with autocorrect

There is an option you can set so that when using the cd command, small typos are automatically corrected. Add the following to your ~/.bashrc:

# cd: autocorrect small typos and use best guess
shopt -s cdspell 

Example:

cd Porjects
# Projects

pwd
# /home/judith/Projects

Also, I recommend adding aliases for your most common typos of commands you regularly use to your ~/bashrc. Which ones that are is highly personal, for me it's e.g. tig:

alias tog='tig'
alias tug='tig'

How to discard ActiveRecord's association cache

You know that ActiveRecord caches associations so they are not loaded twice for the same object. You also know that you can reload an association to make Rails load its data from the database again.

user.posts.reload
# discards cache and reloads and returns user.posts right away
# => [...]

If you want to discard the cache but not query the database (only the next time the association is accessed), you can use reset:

user.posts.reset
# discards cache, but does not load anything yet
user.posts
# SQL query happens to ...

In Chrome 121+ the now supported spec-compliant scrollbar properties override the non-standard `-webkit-scrollbar-*` styles

Up until Chrome 120, scrollbars could only be styled using the various -webkit-scrollbar-* pseudo elements, e.g. to make the scrollbars have no arrows, be rounded, or with additional margin towards their container.

Starting with version 121, Chrome now also supports the spec-compliant properties scrollbar-width and scrollbar-color.
These allow less styling. You may only specify the track and thumb colors, and a non-specific width like auto, thin, or none.

Heads up: You should always use "current_window.resize_to" to resize the browser window in tests

I recently noticed a new kind of flaky tests on the slow free tier GitHub Action runners: Integration tests were running on smaller screen sizes than specified in the device metrics. The root cause was the use of Selenium's page.driver.resize_window_to methods, which by design does not block until the resizing process has settled:

We discussed this issue again recent...

Use <input type="number"> for numeric form fields

Any form fields where users enter numbers should be an <input type="number">.

Numeric inputs have several benefits over <input type="text">:

  • On mobile or tablet devices, number fields show a special virtual keyboard that shows mostly digit buttons.
  • Decimal values will be formatted using the user's language settings.
    For example, German users will see 1,23 for <input type="number" value="1.23">.
  • Values in the JavaScript API or when submitting forms to the server will always use a point as decimal separator (i.e. "1.23" eve...

Configuring Git with .gitconfig

Basic configuration

Please keep this config simple. It should be a starting point for new developers learning Git.

[user]
  name = Your Name
  email = your.name@domain.com

[branch]
  sort = -committerdate
[color]
   ui = auto
[color "branch"]
  current = yellow reverse
  local = yellow
  remote = green
[color "diff"]
  whitespace = white reverse
  meta = blue reverse
  frag = blue reverse
  old = red
  new = green
[color "status"]
  added = green
  changed = yellow
  untracked = cyan
[interactive]
  singlekey = true # Do not requir...

Where to keep project files that should not go to Git

Sometimes you have a file that is related to a project, while not actually being part of it. You'd like to keep them around, but others won't need them – e.g. some notes, a log, or a database dump.

Sure, you have a project directory – but all of it is tracked by Git. A project's tmp/ directory is usually not tracked, but by definition it is not a good place to keep things.

An excluded directory for related files

I suggest you keep your related files in a related-files/ directory within your project(s).

To keep this directory u...

How to configure Selenium WebDriver to not automatically close alerts or other browser dialogs

tl;dr

We recommend configuring Selenium's unhandled prompt behavior to "ignore".

When running tests in a real browser, we use Selenium. Each browser is controlled by a specific driver, e.g. Selenium::WebDriver::Chrome for Chrome.

There is one quirk to all drivers (at least those following the W3C webdriver spec) that can be impractical:
When any user prompt (like an alert) is encountered when trying to perform an action, they will [dismiss the dialog by default](https://w3c....

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

Concurrency issues with find-as-you-type boxes

Find-as-you-type boxes are usually built by observing changes in a text field, and querying the server via AJAX for search results or suggestions when the field has changed.

A common problem with this implementation is that there is no guarantee that AJAX responses are evaluated in the same order as the original requests. The effect for the user is that the search results are flashing back and forth while the user is typing the query, and when the user has stopped typing the last results don't always match the final query.

Workarounds
----...

Best practices: Writing a Rails script (and how to test it)

A Rails script lives in lib/scripts and is run with bin/rails runner lib/scripts/.... They are a simple tool to perform some one-time actions on your Rails application. A Rails script has a few advantages over pasting some prepared code into a Rails console:

  • Version control
  • Part of the repository, so you can build on previous scripts for a similar task
  • You can have tests (see below)

Although not part of the application, your script is code and should adhere to the common quality standards (e.g. no spaghetti code). However, a script...

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

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

When reading model columns during class definition, you must handle a missing/empty database

When doing some meta-programming magic and you want to do something for all attributes of a class, you may need to access connection or some of its methods (e.g. columns) during class definition.

While everything will be fine while you are working on a project that is in active development, the application will fail to boot when the database is missing or has no tables. This means that Raketasks like db:create or db:migrate fail on a freshly cloned project.

The reason is your environment.rb which is loaded for Raketasks and calls...

Bash: How to count and sort requests by IP from the access logs

Example

87.140.79.42 - - [23/Jan/2024:09:00:46 +0100] "GET /monitoring/pings/ HTTP/1.1" 200 814 "-" "Ruby"
87.140.79.42 - - [23/Jan/2024:09:00:46 +0100] "GET /monitoring/pings/ HTTP/1.1" 200 814 "-" "Ruby"
87.140.79.41 - - [23/Jan/2024:09:00:46 +0100] "GET /monitoring/pings/ HTTP/1.1" 200 814 "-" "Ruby"
87.140.79.42 - - [23/Jan/2024:09:00:46 +0100] "GET /monitoring/pings/ HTTP/1.1" 200 814 "-" "Ruby"

Goal

Count and sort the number of requests for a single IP address.

Bash Command

awk '{ print $1}' test.log | sort...