We have deprecated Rack::SteadyETag

Rack::SteadyETag was a Rack middleware that generates the same default ETag for responses that only differ in XOR-masked CSRF tokens or CSP nonces.

We have deprecated Rack::SteadyETag. We instead recommend reconfiguring your Rails app so two requests to the same resource produce the same HTML for a given user.

Rails: Fixing ETags that never match

Every Rails response has a default ETag header. In theory this would enable caching for multiple requests to the same resource. Unfortunately the default ETags produced by Rails are effectively random, meaning they can never match a future request.

Understanding ETags

When your Rails app responds with ETag headers, future requests to the same URL can be answered with an empty response if the underlying content ha...

How Haml 6 changes attribute rendering, and what to do about it

Haml 6 was a major rewrite with performance in mind. To achieve a performance improvement of 1.7x, some design trade-offs had to be made. The most notable change might be the simplified attribute rendering.

In Haml 5, attribute rendering knew two special cases: an attribute with value true would be rendered without a value, an attribute with a falsy value would not be rendered at all. All other values would just be rendered as attribute values.

According to the Haml maintai...

Using Capybara finder methods with arbitrary matching conditions

Capybara has a variety of finder methods like find_button to help you look up DOM elements. There are also matchers like have_field to make expectations during tests.

These methods also have a number of options to influence the lookup. E.g. the :disabled option lets you control whether Capybara will match disabled fields.

If you have a matching condition that cannot be expressed by the existing Capybara opt...

Simple Form: Rendering errors without an appropriate attribute

Usually you add errors to :base in ActiveRecord, in case no appropriate attribute could be used to add the error.

Simple Form doesn't render errors on :base by default, but here a few options how you can render these on demand. For all the options below we use the following example with a Simple Form Bootstrap configuration:

- @user = Backend::User.new
- @user.errors.add(:base, 'First error')
- @user.errors.add...

Rails: Assigning associations via HTML forms

Let's say we have posts with an attribute title that is mandatory.

Our example feature request is to tag these posts with a limited number of tags. The following chapters explain different approaches in Rails, how you can assign such an association via HTML forms. In most cases you want to use Option 4 with assignable values.

The basic setup for all options looks like this:

config/routes.rb

Rails.application.routes.draw do
  root "posts#index"
  resources :posts, except: [:show, :destroy]
end

**db/migrate/...

Rails: Composing an ETag from multiple records

Rails offers the fresh_when method to automatically compute an ETag from the given record, array of records or scope of records:

class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
    fresh_when @user
  end  
  
  
  def index
    @users = User.all.to_a
    fresh_when @users
  end
end

When your view also displays other records (typically associations), those other records should be included in the ETag. You can do so by passing an array of ETaggable objects to fresh_when.

...

Rails: Your index actions probably want strict_loading

By activating strict_loading you force developers to address n+1 queries by preloading all associations used in the index view. Using an association that is not preloaded will raise an ActiveRecord::StrictLoadingViolationError.

I think it's a good default to activate strict_loading in your controllers' #index actions. This way, when a change introduces an n+1 query, you...

How to enable template coverage support for simplecov

Since Ruby 3.2.0 you can measure coverage support for eval statements and support has been added for the simplecov gem as well.

This allows to track coverage across ruby templates such as haml, erb, ...

Simply set this within simplecov

SimpleCov.start do
  enable_coverage_for_eval
end

Rails migration: Changing a column type without losing the content

The change_column method for rails migrations support casting with a custom SQL statement. This allows us to change a column type and keep the former content as the new type. This way, we can for example prepare an address number column to hold German address numbers, which can contain letters:

Example (in most cases not a good idea!)

class ChangeAnIntegerColumnToString < ActiveRecord::Migration[6.1]
  def up
    change_column :users, :address_number, 'varchar USING CAST(rating AS varchar)'
  end

  def down
    change_column ...

Rails Partials

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: 'partial' 

This will render a _partial.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: ...

How to turn images into inline attachments in emails

Not all email clients support external images in all situations, e.g. an image within a link. In some cases, a viable workaround is to turn your images into inline attachments.

Note

Rails provides a simple mechanism to achieve this:

This documentation makes it look like you have to care about these attachments in two places. You have to create the attachment in t...

Rails: Encrypting your database information using Active Record Encryption

Since Rails 7 you are able to encrypt database information with Active Record. Using Active Record Encryption will store an attribute as string in the database. And uses JSON for serializing the encrypted attribute.

Example:

  • p: Payload
  • h: Headers
  • iv: Initialization Vector
  • at: Authentication Tag
{ "p": "n7J0/ol+a7DRMeaE", "h": { "iv": "DXZMDWUKfp3bg/Yu", "at": "X1/YjMHbHD4talgF9dt61A=="} }

Note this before encrypting attributes with Active Record:
...

git: find the version of a gem that releases a certain commit

Sometimes I ran across a GitHub merge request of a gem where it was not completely obvious in which version the change was released. This might be the case for a bugfix PR that you want to add to your project.

Git can help you to find the next git tag that was set in the branch. This usually has the name of the version in it (as the rake release task automatically creates a git tag during release).

git name-rev --tags <commit ref>

Note

The more commonly used git describe command will return the last tag before a c...

Rails: Accessing helper methods from a controller

In Rails 5+ you can access a helper from a controller using the helpers method:

# Inside a controller action
helpers.link_to 'Foo', foo_path

In older Rails versions you can use view_context instead:

# Inside a controller action
view_context.link_to 'Foo', foo_path

Dynamic super-overridable methods in Ruby – The Pug Automatic

How a macro can dynamically define a method that can be overridden with super in the same class.

You can use the with_module_inheritance helper below if you want. It can be handy to make parts of a modularity trait super-able.

# ./lib/ext/module/with_module_inheritance.rb
#
# This macro allows you to define methods in a modularity trait that can be
# modified using the `super` keyword
# See https://thepugautomatic.com/2013/07/dsom/
module WithModuleInheritance
  def with_module_inher...

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

Jasmine: Mocking ESM imports

In a Jasmine spec you want to spy on a function that is imported by the code under test. This card explores various methods to achieve this.

Example

We are going to use the same example to demonstrate the different approaches of mocking an imported function.

We have a module 'lib' that exports a function hello():

// lib.js

function hello() {
  console.log("hi world")
}

export hello

We have a second module 'client' that exports a function helloTwice(). All this does is call hello() ...

Jasmine: Creating DOM elements efficiently

Jasmine specs for the frontend often need some DOM elements to work with. Because creating them is such a common task, we should have an efficient way to do it.

Let's say I need this HTML structure:

<ul type="square">
  <li>item 1</li>
  <li>item 2</li>
</ul>

This card compares various approaches to fabricating DOM elements for testing.

Constructing individual elements

While you can use standard DOM functions to individually create and append elements, this is extremely verbose:

let list = document.createElement('...

Jasmine: Cleaning up the DOM after each test

Jasmine specs that work with DOM elements often leave elements in the DOM after they're done. This will leak test-local DOM state to subsequent tests.

For example, this test creates a <spoiler-text> element, runs some expectations, and then forgets to remove it from the DOM:

describe('<spoiler-text>', function() {
  it ('hides the secret until clicked', function() {
    let element = document.createElement('spoiler-text')
    element.secret = 'The butler did it'
    document.body.appendChild(element)
 ...

Variable fonts: Is the performance trade-off worth it? - LogRocket Blog

Variable fonts are popular for two reasons: they expand design possibilities and improve website performance. While the former statement is definitely true since variable fonts do provide infinite typographical choices, the latter only holds under certain conditions.

Chrome DevTools: Treasure (Overview)

tl;dr

The Chrome DevTools are a neat collection of tools for the daily work as a web developer. If you're lucky, you'll maybe find some handy stuff in here.

Analysing

Breakpoints

  • [Breakpoints on HTML Elements](https://makandracards.com/makandra/517982-chrome-devtools...

Chrome DevTools: DOM Breakpoints - Breakpoints on HTML Elements

tl;dr

In Chrome DevTools in the Elements tab or in Firefox in the Inspector tab you can right click on an element and choose Break on to debug changes related to this element.

Example

DOM Breakpoints can be quite useful to quickly find the JavaScript that is responsible for some (unexpected) behavior. You can use DOM Breakpoints for debugging subtree modifications, attribute modifications or node removal.

Here you can see a very simple example that shows what JavaScript lines are responsible for ...

Debug flaky tests with an Unpoly observeDelay

The problem

Unpoly's [up-observe], [up-autosubmit] and [up-validate] as well as their programmatic variants up.observe() and up.autosubmit() are a nightmare for integration tests.

Tests are usually much faster than the configured up.form.config.observeDelay. Therefore, it may happen that you already entered something into the next field before unpoly updates that field with a server response, discarding your changes.

The steps I wait for active ajax requests to complete (if configured) and capybara-lockstep can catch some ...