Running "bundle update" without arguments might break your application

Calling bundle update (without arguments) updates all your gems at once. Given that many gems don't care about stable APIs, this might break your application in a million ways.

To stay sane, update your gems using the applicable way below:

Projects in active development

Update the entire bundle regularily (e.g. once a week). This ensures that your libraries are up-to-date while it's easy to spot major version bumps which may break the app.

Projects that have not been updated in a while

  1. [Update a single gem conservatively](htt...

Calling a helper method with the same name as your current partial

Partials always define a local variable with the same name as themselves. E.g. when you are in _recent_users.html.erb, a local variable recent_users will be defined and overshadow any helper method that is also called recent_users().

If you would like to use a helper method recent_users() in a partial _recent_users.html.erb you can say this in the partial template:

<% recent_users = self.recent_users() %>
<% recent_users.each do |user| %>
  ...
<% end %>

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

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

Fix: esbuild assets are missing after capistrano deploy

Issue: You have an app using jsbundling-rails and esbuild. After deploy, the assets built by esbuild are missing in public/assets.

Solution: Add app/builds to your git repo (by adding a app/builds/.keep file).

Something in sprockets is caching paths and refuses to accept files in "unknown" locations.

Fix PNG colors in IE, old Safaris and new Firefoxes

Some browsers render PNG images with color profiles and other shenanigans, some don't.

The cleanest way to have consistent colors across browsers is to convert all your images to a standard color profile, strip the image's original profile and attach the standard profile.

If you can't be bothered to convert color profiles, a quicker (but less effective) method is to remove some PNG chunks from your files.

With Geordi

[Geordi](https://git...

Writing strings as Carrierwave uploads

When you have string contents (e.g. a generated binary stream, or data from a remote source) that you want to store as a file using Carrierwave, here is a simple solution.

While you could write your string to a file and pass that file to Carrierwave, why even bother? You already have your string (or stream).
However, a plain StringIO object will not work for Carrierwave's ActiveRecord integration:

>> Attachment.create!(file: StringIO.new(contents))
TypeError: no implicit conversion of nil into String

This is because Carrierwav...

PostgreSQL: How to show database size

SELECT pg_size_pretty(pg_database_size('some-database'));

Example

SELECT pg_size_pretty(pg_database_size('cards_p'));
----------------
 13 GB
(1 row)
SELECT pg_database_size('cards_p');
 pg_database_size 
------------------
      13524832927
(1 row)

Related

The Easiest Way to Parse URLs with JavaScript

A very clever hack to parse a structured URL object is to create a <a> element and set its href to the URL you want to parse.

You can then query the <a> element for its components like schema, hostname, port, pathname, query, hash:

var parser = document.createElement('a');
parser.href = 'http://heise.de/bar';
parser.hostname; // => 'heise.de'
pathname = parser.pathname; // => '/bar'

if (pathname[0] != '/')
  pathname = '/' + pathname // Fix IE11

One advantag...

Icon font vertical alignment in Windows

I had an issue with icons from an icon font aligning differently on Linux, iOS and Windows (seemingly browser-independent). With vertical-align:middle, they aligned properly on Linux, iOS and macOS, whereas with a vertical-align of -18%, it looked good on Windows and iOS, but not Linux.

Further investigation showed that not only icons, but also normal capital letters aligned differently. No setting of vertical-align could fix this, neither top, bottom, middle, nor additional paddings or margins. It seems like browsers take the...

Hiding the clear input button of Edge (with EdgeHTML engine)

Edge (and some versions of Internet Explorer, like IE11) use to render a × clear input button on text fields. While this is intended as a nicety for users, it comes in annoying when you've built and styled your own clear input button.

Hide the Edge × with this pseudo selector:

input::-ms-clear
  display: none

Differences between transactions and locking

Web applications can be used by multiple users at the same time. A typical application server like Passenger has multiple worker processes for a single app. In a distributed deployment setup like we use at makandra you will even have multiple application servers, each with their own worker pool.

This means that your code needs to deal with concurrent data access. The two main tools we use to cope with concurrency are database transactions and distributed locks. These two are not interchangeable. You ca...

Double loading issue with Ruby default gems

Ruby includes many standard gems that are bundled into the Ruby installation. Here is an example for the gem strscan that will be displayed as default:

gem list strscan     

*** LOCAL GEMS ***

strscan (default: 3.0.1)

It is still possible to have newer version of a gem installed beside the default version:

gem install strscan  
Fetching strscan-3.0.3.gem
Building native extensions. This could take a while...
Successfully installed strscan-3.0.3
1 gem installed
gem list strscan   

*** LOC...

How to debug issues with zeitwerk and Rails

In case you have trouble with the zeitwerk autoloader, you can check out the documentation Autoloading and Reloading Constants and Classic to Zeitwerk HOWTO for some debugging hints.

For myself it was useful to print the registered constants and the file references during the boot. Therefore you need to add Rails.autoloaders.log! at the end of your config/application.rb file. You could also run `bin...

Waiting for page loads and AJAX requests to finish with Capybara

If you're using the Capybara webdriver, steps sometimes fail because the browser hasn't finished loading the next page yet, or it still has a pending AJAX request. You'll often see workarounds like

When I wait for the page to load
Then ...

Workarounds like this do not work reliably, will result in flickering tests and should be avoided. There is no known reliable way to detect if the browser has finished loading the page.

Solution

Instead you should wait until you can observe the result of a page load. E.g. if y...

ActiveType 1.2 supports "change_association"

With ActiveType 1.2 you can modify associations (has_many etc.) after they have been defined.

One common use case for this is to change an association inside a form model, like this:

class Credential < ActiveRecord::Base
end

class User < ActiveRecord::Base
  has_many :credentials
end

class SignUpCredential < ActiveType::Record[Credential]
end

class SignUp < ActiveType::Record[User]
  change_association :credentials, class_name: 'SignUpCredential'
end

Now, if you load `credentials...

CSS: Don't target multiple vendor-prefixed pseudo-elements in a single rule

Some pseudo-elements need to be addressed with vendor prefixes. E.g. ::selection is not supported by Firefox, you need to use ::-moz-selection instead.

What you cannot do is to define a single CSS rule to address both the standard and vendor-prefixed form:

::selection, ::-moz-selection {
  background-color: red;
}

This rule will be ignored by all browsers. The reason is that if a browser doe...

Rails: namespacing models with table_name_prefix instead of table_name

When you want to group rails models of a logical context, namespaces are your friend. However, if you have a lot of classes in the same namespace it might be tedious to specify the table name for each class seperately:

class Accounting::Invoice < ApplicationRecord
  self.table_name = 'accounting_invoices'
  ...
end

class Accounting::Payment < ApplicationRecord
  self.table_name = 'accounting_payments'
  ...
end

A replacement for the self.table_name-assignment is the table_name_prefix in the module definition:

modu...

Project maintenance: four levels of code quality

Code quality can be measured in four levels:

  1. (Working code)
  2. Reliable code (minimum)
  3. Readable code (ok for short-lived code)
  4. Changeable code (standard level)

The code quality of a project directly impacts its maintainability.

Generally you should aim for level 3. If the code will stay for less than a few months, it may stay at level 2. Never go below level 1.

0. Working code

You have implemented that feature and it works. Congrats! You have reached level zero, which means three levels of code quality lie ahead.

First, m...

Rails: Remove Blank Values from Collections

tl;dr

Since Rails 6.1+ you can use .compact_blank or .compact_blank! to remove blank values from collections (e.g. arrays).

Remove nil values from an array

['foo', nil].compact
# => ['foo']

# You can use the splat operator to ignore nil values when constructing an array
['foo', *nil]
# => ['foo']

Remove blank values from collections

Array

array = [1, "", nil, 2, " ", [], {}, false, true]

# Any Rails version
array.reject(&:blank?)
# => [1, 2, true]

# Since Rails 6.1+
array.compact_blank
# ...

Ruby constant lookup: The good, the bad and the ugly

In Ruby, classes and modules are called constants. This card explains how Ruby resolves the meaning of a constant.

The good

E. g. in the following example, Array could mean either Foo::Array or simply Array:

class Foo
  def list
    Array.new
  end
end

What Ruby does here is to see if the name Array makes sense inside of Foo::, and if that fails, resolves it to ::Array (without a namespace).

The bad

This is relevant for old Ruby versions. Ruby 2.5+ removes top-level constant lookup whi...

CSS Support Guide for Email Clients

CSS support in major e-mail clients is horrible.

This will give you an overview what you will not be able to use across all clients.

See also

Postgresql: Paginate and count in one query using window functions

When paginating records, we usually need to know the number of total records in order to render pagination links. Popular pagination libraries like will_paginate or Kaminari do this for us by simply issuing an extra query, like this:

SELECT post.* FROM posts LIMIT 20 OFFSET 100;

SELECT COUNT(*) FROM posts;   

This is fine most of the time. But rarely, you might have very complicated WHERE conditions or a subquery that takes time to run. In thes...

JavaScript: Testing whether the browser is online or offline

You can use the code below to check whether the browser can make connections to the current site:

await isOnline() // resolves to true or false

The code

The isOnline() function below checks if you can make real requests by re-fetching your site's favicon. If the favicon cannot be downloaded within 6 seconds, it considers your connection to be offline.

async function isOnline({ path, timeout } = {}) {
  if (!navigator.onLine) return false

  path ||= document.querySelect...