Updated: Automated "git bisect" will make your day

Added methods to keep the line number steady while you time-travel between commits:

How to create a terminal progress indicators in Ruby

For long running scripts it is useful to show a indicator for the progress in the terminal. Alternatively you can use a gem like paul/progress_bar.

count = User.count
index = 0

User.find_each do |user|
  printf("Progress: %.2f%%\r", index.to_f / count * 100)
  user.update!(role: 'member')
  index += 1
end

Preview video

Image

Updated: Jasmine: Creating DOM elements efficiently

I have moved away from creating fixture elements using CSS selectors. While CSS can be very concise, it can be hard to recognize the created elements, and how they are nested within each other.

A more visual alternative is to embed a string of HTML into your test. My specs often have a function htmlFixtures() that parses the HTML and returns a reference to all created elements:

let [list, item1, item2] = htmlFixtures(`
  <ul type="square">
    <li>item 1</li>
    <li>item 2</li>
  </ul>
`)

Because the effective HTML is visible...

How to automatically optimize SVG files with esbuild

SVG files often contain redundant information, like editor metadata or hidden elements. When esbuild handles your static assets, you can easily optimize SVG files using svgo as a plugin. Here is how to do it.

Adding svgo as an esbuild plugin

  1. Add the svgo package to your project's package.json
  2. Adjust your esbuild.config.js like so:
const esbuild = require('esbuild')
const svgo = require('svgo')

const options = {
  // ...
  loader: {
    // ...
    '.svg': 'copy', // this may be different...

Rails: Using PostgreSQL full-text search without a gem

PostgreSQL can cosplay as a full-text search engine. It doesn't have the features or fidelity of ElasticSearch or Algolia, but it's good enough if you just need to search and rank large volumes of text.

This card will teach you how to index, search and rank your Rails models in a PostgreSQL full-text index. We will do this without using any gems aside from ActiveRecord. While there are gems like pg_search or pg_fulltext, manual integration requires very...

RSpec: executing specs by example id (or "nesting index")

There are several ways to run a single spec. I usually copy the spec file path with the line number of the example and pass it to the RSpec binary: bin/rspec spec/models/user_spec.rb:30 (multiple line numbers work as well: :30:36:68). Another is to tag the example with focus: true or to run the example by matching its name.

In this card I'd like to ...

Rails: Overwriting default accessors

All columns of a model's database table are automagically available through accessors on the Active Record object.

When you need to specialize this behavior, you may override the default accessors (using the same name as the attribute) and simply call the original implementation with a modified value. Example:

class Poet < ApplicationRecord

  def name=(value)
    super(value.strip)
  end

end

Note that you can also avoid the original setter and directly read/write from/to the instance's attribute storage. However this is dis...

How to not die with ActionView::MissingTemplate when clients request weird formats

When HTTP clients make an request they can define which response formats they can process. They do it by adding a header to the HTTP request like this:

Accept: application/json

This means the client will only understand JSON responses.

When a Rails action is done, it will try to render a template for a format that the client understand. This means when all you are HTML templates, a request that only accepts application/json will raise an error:

An ActionView::MissingTemplate occurred in pages#foo:
  Missing templa...

Flexbox: flex-basis vs. width vs. min-width vs. max-width

Within a Flexbox layout, there are multiple CSS attributes that may affect a child's basis (the initial width before flexing). You might be confused how flex-basis, width, min-width and the intrinsic width of your content play together.

The attached article explains the differences. In summary:

  • If a flex-basis is set, that is used as the basis
  • If no flex-basis is set, the width is used as the basis
  • If neither flex-basis nor width is set, the content...

HTML forms with multiple submit buttons

Most forms have a single submit button that will save the record when pressed.

Sometimes a form needs additional submit buttons like "accept" or "reject". Such buttons usually attempt a state transition while updating the record.

To process a form with multiple buttons, your server-side code will need to know which button was pressed. To do so you can give each submit button a different [formaction] attribute. This will override the ...

Rails routing: Using constraints to avoid "Missing template" errors

You can use constraints in your routes.rb to avoid getting ActionView::MissingTemplate errors when wrong routes are called. Instead, the user will see a 404.

If you want multiple routes to use the same constraint you can use the block syntax:

constraints(format: 'html') do
  resources :pages
  resources :images
end

If you want constraints only on certain routes, you can do:

get '/users/account' => 'users#account', constraints: { format: 'html' }

Tip

You can also avoid this error type through [format con...

Haml Whitespace Preservation (or: Fixing Textarea Indentation in Haml)

Haml renders HTML with indentation reflecting the nesting level of elements. When it comes to white-space preserving content, this may become a problem: the content will be rendered including the HTML indentation.

Problematic: Preserved Indentation

.nest
  %span Reference
  %pre
    = content
<div class="nest">
    <span>Reference</span>
    <pre>
        Hello
        World
    </pre>
</div>

Image

Better: Without Extra Indentation

Render with tilde ~ instead of equal...

Why your Cucumber feature loses cookies when run under Selenium

When your Cucumber feature seems to forget cookies / sessions when you run it with Selenium check if the test travels in time like here:

Given the date is 2017-10-20
When I sign in
Then I should see "Welcome!"

What happens here is that the Rails application serving pages runs in 2017, but the process running your browser still lives today. This huge gap in time will expire most cookies immediately.

If all you need is to freeze the time to a date, a workaround is to travel to the future instead.

Clean code: Avoiding short versions in command options

This card is a general reminder to avoid the short version of a command option in shared code. It's much easier to understand a command and search for an option when it's written out.

You can still use the short version of the options in your own terminal or in code snippets that are more useful when they are very compact. For the latter case you often see a description of the command options one line below e.g. in posts on stackoverflow.

Example good (in code):

/usr/bin/gpg --output password.txt --decrypt password.txt.gpg

...

Git: Restore

tl;dr

git checkout is the swiss army of git commands. If you prefer a semantically more meaningful command for restoring tasks, use git restore instead.

With this command you can ...

  • ... do unstaging - git restore --staged
  • ... discard staged changes - git restore --staged --worktree
  • ... discard unstaged changes - git restore
  • ... restore deleted files - git restore
  • ... restore historic versions - git restore --source
  • ... recreate merge conflicts - git restore --merge
  • ... specifiy...

Capybara: Working with invisible elements

When Capybara locates elements in the DOM, by default it allows only accessing visible elements -- when you are using a driver that supports it (e.g. Selenium, not the default Rack::Test driver).

Consider the following HTML:

<div class="test1">One<div>
<div class="test2">Two</div>

With some CSS:

.test1 { display: block }
.test2 { display: none }

We will be using Capybara's find below, but this applies to any Capybara finder methods.

Default: visible: :visible

As described above, by default Capybara finds ...

Defining and calling lambdas or procs (Ruby)

Ruby has the class Proc which encapsulates a "block of code". There are 2 "flavors" of Procs:

  • Those with "block semantics", called blocks or confusingly sometimes also procs
  • Those with "method semantics", called lambdas

lambdas

They behave like Ruby method definitions:

  • They are strict about their arguments.
  • return means "exit the lambda"

How to define a lambda

  1. With the lambda keyword

    test = lambda do |arg|
      puts arg
    end
    
  2. With the lambda literal -> (since Ruby 1.9.1)
    ...

ActiveStorage: How to add a new preprocessed named version

Given there is a user with an attachable avatar:

class User < ApplicationRecord
  has_one_attached :avatar
end

If you want to add a preprocessed version follow these steps:

  1. Add the named version and deploy
class User < ApplicationRecord
  has_one_attached :avatar do |attachable|
    attachable.variant :preview, resize_to_fit: [177, 177 * 9 / 16], preprocessed: true
  end
end
  1. Preprocess this version for all existing records `bundle exec rails runner 'User.find_each { |user| user.avatar.variant(:preview).proc...

ActiveStorage: How to copy / clone an attachment from one record to another

Given there is a user with an attachable avatar:

class User < ApplicationRecord
  has_one_attached :avatar
end

You can copy the avatar from one user to another user with the code below:

user_1 = User.first
user_2 = User.create!(
  avatar: {
    io: StringIO.new(user_1.avatar.download),
    filename: user_1.avatar.blob.filename.to_s,
    content_type: user_1.avatar.blob.content_type.to_s,
  }
)

Note: For large attachments you might need to use a different approach to avoid memory issues.

Using Low-Level Prompts for High-Accuracy AI Coding

The key to unlocking the full potential of LLMs in coding lies in crafting precise prompts. The main challenge is learning how to structure prompts effectively to guide the model toward accurate results. Further evidence supporting this is the fact that Aider already writes ~70% of its own code (as of 02/2025). However, when starting out, your results may fall short of efficiently generating large portions of your code with the...

Git commands to discard local changes

Use case

You have uncommited changes (you can always check by using git status), which you want to discard.

Context

Now there are several options to discard these depending on your exact situation.
The headlines will differentiate the cases whether the files are staged or unstaged.

  1. Staged and unstaged changes
  2. [Staged changes](https://makandracards.com/makandra/516559-git-commands-to-discard-local-changes#s...

RSpec: Tagging examples and example groups

In RSpec you can tag examples or example groups with any tags you like simply by saying

describe ReportCreator, slow: true do
  # ..
end

describe ReportCreator do
  it 'generates reports', slow: true do
    # ...
  end
end

You can then only run examples with these tags.

rspec --tag slow
rspec -t slow

# Using the parallel_tests gem
rake "parallel:spec[,,--tag slow]"

Or you can run all examples except the ones with a certain tag:

rspec --tag ~slow # note the ~
rspec -t ~slow

# Using the parallel_tests gem
r...

PSA: "index: true" in Rails migrations does not work as you'd expect

Several Rails migration methods accept index: true as an option to create an index. In some cases (like #add_column), this option is silently discarded. Know what you are doing, or use #add_index instead.

Example

Consider the following migration.

class CreateExamples < ActiveRecord::Migration
  def change
    create_table :examples do |t|
      t.references :category, index: true
      t.boolean :positive, index: true
      t.integer :number_of_participants, index: true
    end

    add_reference :examples, :user, index: tr...