Sending newsletters via rapidmail with SMTP and one-click unsubscribe

If you need to implement newsletter sending, rapidmail is a solid option.

Support is very fast, friendly and helpful, and the initial setup is simple. Since rapidmail works via SMTP, you can simply ask the Ops team to configure SMTP credentials for your application.

You also do not need to use rapidmail’s built-in newsletter feature. Instead, you can send emails as transactional mails, which allows you to keep the entire newsletter logic inside your application.

One thing to keep an ey...

Careful when using Time objects for generating ETags

You can use ETags to allow clients to use cached responses, if your application would send the same contents as before.

Besides what "actually" defines your response's contents, your application probably also considers "global" conditions, like which user is signed in:

class ApplicationController < ActionController::Base

  etag { current_user&.id }
  etag { current_user&.updated_at }

end

Under the hood, Rails generates an ETag header value like W/"f14ce3710a2a3187802cadc7e0c8ea99". In doing so, all objects from that etagge...

Rails developers: Have better context in Git diffs

Git diffs show the surrounding contexts for diff hunks. It does so by applying regular expressions to find the beginning of a context. When it comes to Ruby, however, it will not find method heads and travel up to the class definition:

@@ -24,7 +24,7 @@ class TicketPdf # <=== Actually expected here: the method definition
     ApplicationController.render(
       "tickets/index.html.haml",
       layout: "tickets",
-      assigns: { tickets: tickets }
+      assigns: { tickets: tickets, event_name: event_name }
     )
   end
 end
```...

Deterministic ordering of records by created_at timestamp

Creating records in specs can be so fast that two records created instantly after one another might have the same created_at timestamp (especially since those timestamps don't have an indefinitely high resolution). When ordering lists by timestamps, you should therefore always include a final order condition using the primary key of the table.

class Photo < ActiveRecord::Base
  scope :by_date, -> { order('created_at DESC, id DESC') }
end

Photo.by_date

Remember to include the id field in the database index.

TypeScript: Enable strict-boolean-expressions for Safe Nullish Checks

You may remember to use the || operator with caution to set defaults. We'll see that && and other conditionals come with the same limitations. However, TypeScript and eslint can make this a lot safer for us.

TL;DR

  • && can be used as non-null safe access
  • || can be used for null/undefined fallback values
  • Danger: falsey values give false negatives and bypass checks wrongly
  • Prefer ?? (nullish coalescing) or enable strict-boolean-expressions ...

Ruby: How to use prepend for cleaner monkey patches

Let's say you have a gem which has the following module:

module SuperClient

  def self.foo
    'Foo'
  end
  
  def bar
    'Bar'
  end

end

For reasons you need to override foo and bar.

Keep in mind: Your code quality is getting worse with with each prepend (other developers are not happy to find many library extensions). Try to avoid it if possible.

  1. Add a lib/ext/super_client.rb to your project (see How to organize monkey patches in Ruby on Rails projects)
  2. Add the extension, which ov...

Defining new elements for your HTML document

Browsers come with a set of built-in elements like <p> or <input>. When we need a new component not covered by that, we often build it from <div> and <span> tags. An alternative is to introduce a new element, like <my-element>.

When a browser encounters an unknown element like <my-element>, the browser will proceed to render <my-element>'s children. The visual rendering of your page will not be affected.

Tip

If you care about their HTML being valid, your new element should contain a dash character (-) to mark it as a ...

How to reload a belongs_to association

To reload a single-item association in Rails 5+, call #reload_<association>:

post.reload_author

In older Railses you can say

post.author(true)

Locally testing a website on its real domain

In rare circumstances, you want to use a websites full domain (say https://mywebsite.com) while testing in dev mode. This can be useful if you need to test third party integrations like embeds, cookie banners, Google Tag Manger or other integrations that allowlist your actual domain.

To achieve this, we will have to

  • make our system resolve mywebsite.com to localhost,
  • run a reverse proxy on localhost:443 with a (locally signed and accepted) SSL certificate for mywebsite.com,
  • forward the traffic to our actual dev server.

On l...

TypeScript: Get in Shape with Structural Typing

TypeScript basically uses structural typing, which is conceptually quite similar to duck typing, but with static compile-time type checking. We'll explore what this means in practice.

TypeScript is a superset of JavaScript, meaning TypeScript compiles down to native JavaScript syntax and checks type consistency only at compile time.

Idea of Structural Typing

TypeScript only wants to know whether the shapes of two objects are identical:

interface Point2D {
  x: number;
  y: number;
}

function printPoint(p: Point2D) {
  c...

RSpec: Debug flickering test suites with rspec --bisect

In modern default RSpec configurations, your tests are usually run in random order. This helps to detect "flickering" tests that only fail when run in a certain order.

The reason for this are tests that have side effects causing other tests to fail later. The hard part is to find the offending test.

Enter rspec --bisect:

  1. Say you have a flickering test that passes on its own, but you just saw it fail in a full test run. At the top of the RSpec output, you will see a message like Randomized with seed 12345. Take a note of the number....

Passive event listeners may speed up your scroll and touch events

Scroll and touch event listeners tend to be computationally expensive as they are triggered very often. Every time the event is fired, the browser needs to wait for the event to be processed before continuing - the event could prevent the default behavior. Luckily there is a concept called passive event listeners which is supported by all modern browsers.

Below are the key parts quoted from WICG's explainer on passive event listeners. See [this demo video](https://www.youtube.com/watch?v=NPM6172...

Linux: Open a file with the default application

If you are on a Linux shell and want to open a file with whatever default application is configured for that type, this often works:

xdg-open Quote.odt
xdg-open invoice.pdf
xdg-open index.html

Pro Tip

Make an alias so you have a simpler API (like Mac OS): alias open=xdg-open or alias x=xdg-open.

Background

You can choose your "Default applications" via UI in the Ubuntu "Settings" application (gnome-control-center). This is just a very rough setting (e.g. open Photos with Shotwell Viewer).

If a certain file...

RSpec: How to retry examples

In some projects we have issues with flaky tests. The best default is to fix them all. But in some cases it might be a pragmatic way to retry them for a limit number of times.

Notes:

**...

Git: Improve your commits by reviewing changes one-by-one

Git commits should be very deliberate, and only contain changes that you really want to be in there. In order to reduce the chance to accidentally commit something you didn't intend, review your changes before committing.

My preferred way of doing this is (only using git)

git add --intent-to-add . # Add all paths (including new files), but not their contents
git add -p

Git will now show you all your changes in small chunks and ask you in an interactive mode whether you really want to add them.

The most helpful commands ...

Heads up: JavaScript does not like big numbers

In a JavaScript console, type this:

> 9112347935156469760
9112347935156470000

Ooops. And that's not a float!

This occurs because JavaScript uses double precision floats to store numbers.

So according to IEEE floating point definition only numbers between -(2^53 - 1) (-9007199254740991) and 2^53 - 1 (9007199254740991) can safely be represented in JavaScript.

Number.MAX_SAFE_INTEGER will return the largest integer that can accurately be represented.

**For arbitrary large n...

CSS: The inset CSS shorthand

The inset CSS property is a shorthand that corresponds to the top, right, bottom, and/or left properties. It has the same multi-value syntax of the margin shorthand.

Example

<div class="outer">
  <div class="inner">
    Some text
  </div>
</div>
.outer {
  background-color: cyan;
  position: relative;
  width: 500px;
  height: 500px;
}

Top, right, bottom and left

https://jsfiddle.net/jqx68wem/

.inner {
  background-color: darkCyan;
  position: absolute;
  top: 10px;
  right: 10px;
  bottom: 10p...

How to simulate limited bandwidth in Google Chrome and Firefox

Your development machine is usually on a very good network connection.
To test how your application behaves on a slow network (e.g. mobile), you can simulate limited bandwidth.

Chrome

  • Open the dev tools (Ctrl+Shift+I or F12) and switch to the "Network" tab
  • In the row below the dev tool tabs, there's a throttling dropdown which reads "Online" by default.
  • Inside the dropdown, you will find a few presets and an option to add your own download/upload/latency settings.

Firefox

  • Open the dev tools (Ctrl+Shift+I or F12) and switc...

Ruby object equality

TLDR

if you define a equality method for a class you must also implement def hash.

Ruby has a lot of methods that have to do something with equality, like ==, ===, eql?, equal?. This card should help you differentiate between those and give you hints on how to implement your own equality methods in a safe manner.

Differences between the methods

for everyday use: ==

When you compare two objects in Ruby, you most often see the use of foo == bar. By default the == operator inherits from Object and is impl...

Updated: Bash functions to provide repository context for LLM chats

Documented a repomix that allows you to bundle the XML repository context with custom LLM instructions. I have mine located at ~/.config/repomix/instruction.md

ActiveRecord: Cleaning up your database with ignored_colums

Leaving old unused DB columns around after a migration is confusing for other developers. However, dropping columns too eagerly might also cause problems and extra work. If you want to mark columns for future deletion, but you are unsure, whether you can simply drop them right now, use these tools:

Add a comment to your DB schema

With schema comments you can add a comment like LEGACY as of yyyy-mm-dd to your DB schema.

Ignore the column

With [...

Debugging failed AJAX requests with better_errors

better_errors is an awesome gem for enhanced error pages in development, featuring a live-REPL for some light debugging.

To debug the exception you got on an AJAX-Request, visit /__better_errors on your app's root path (e.g. http://localhost:3000/__better_errors). It shows the error page for the last exception that occurred, even when it has been triggered by an AJAX request.

You can even open files from better_errors with RubyMine on Linux.

Using partials in Rails views

Rails partials have a lot of "hidden" features and this card describes some non-obvious usages of Rails Partials.

Rendering a basic partial

The most basic way to render a partial:

render partial: 'weather' 

This will render a _weather.html.erb file. Notice how all partials need to be prefixed with _.

It's possible to define local variables that are only defined in the partial template.

# _weather.html.erb
<h1>The weather is <%= condition %></h1>

# index.html.erb
render partial: 'weather', locals: { condition: ...