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

Limitations of navigator.onLine

While you can use the built-in function navigator.onLine (sic), it is only a hint for whether the device can access the Internet.

When navigator.onLine === false you know for certain that the user device has no connection to the Internet. This mea...

How to solve Selenium focus issues

Selenium cannot reliably control a browser when its window is not in focus, or when you accidentally interact with the browser frame. This will result in flickering tests, which are "randomly" red and green. In fact, this behavior is not random at all and completely depends on whether or not the browser window had focus at the time.

This card will give you a better understanding of Selenium focus issues, and what you can do to get your test suite stable again.

Preventing accidental interaction with the Selenium window
--------------------...

Regex: Be careful when trying to match the start and/or end of a text

Ruby has two different ways to match the start and the end of a text:

  • ^ (Start of line) and $ (End of line)
  • \A (Start of string) and \z (End of string)

Most often you want to use \A and \z.

Here is a short example in which we want to validate the content type of a file attachment. Normally we would not expect content_type_1 to be a valid content type with the used regular expression image\/(jpeg|png). But as ^ and $ will match lines, it matches both content_type_1 and content_type_2. Using \A and \z will wo...

Squashing several Git commits into a single commit

This note shows how to merge an ugly feature branch with multiple dirty WIP commits back into the master as one pretty commit.

Squashing commits with git rebase

What we are describing here will destroy commit history and can go wrong. For this reason, do the squashing on a separate branch:

git checkout -b squashed_feature

This way, if you screw up, you can go back to your original branch, make another branch for squashing and try again.

Tip

If you didn't make a backup branch and something ...

You are not using filter_map often enough

Somewhat regularly, you will need to filter a list down to some items and then map them to another value.

You can of course chain map and compact, or select/filter and map, but Ruby 2.7 introduced a method for this exact purpose: filter_map.

So instead of

>> [1, 2, 3, 4, 5, 6].map { |i| i * 2 if i.even? }.compact
=> [4, 8, 12]

or

>> [1, 2, 3, 4, 5, 6].select(&:even?).map { |i| i * 2 }
=> [4, 8, 12]

you can just do

>> [1,...

Josh McArthur: Fancy Postgres indexes with ActiveRecord

I recently wanted to add a model for address information but also wanted to add a unique index to those fields that is case-insensitive.
The model looked like this:

create_table :shop_locations do |t|
  t.string :street
  t.string :house_number
  t.string :zip_code
  t.string :city
  t.belongs_to :shop
end

But how to solve the uniqueness problem?

Another day, another undocumented Rails feature!

This time, it’s that ActiveRecord::Base.connection.add_index supports an undocumented option to pass a string argument as the v...

ruby-sass: Do not use comments between selector definitions

Sass lets you easily specify multiple selectors at once like this:

.some-block
  &.has-hover,
  &:hover
    outline: 1px solid red

This will add a red outline on either real hover or when the has-hover class is present. However, adding a comment will void the definition of that line:

.some-block
  &.has-hover, // From hoverable.js <-- DON'T
  &:hover
    outline: 1px solid red

... will simply drop the &.has-hover part in ruby-sass(deprecated). [sassc](https://rubygems.org/g...