Haml: Generating a unique selector for an element

Having a unique selector for an element is useful to later select it from JavaScript or to update a fragment with an Unpoly.

Haml lets you use square brackets ([]) to generate a unique class name and ID from a given Ruby object. Haml will infer a class attribute from the given object's Ruby class. It will also infer an id attribute from the given object's Ruby class and #id method.

This is especially useful with ActiveRecord instances, which have a persisted #id and will hence generated the same selector ov…

Introduction to Google Tag Manager (for web developers who know Google Analytics)

As a web developer, you know Google Analytics (GA). Probably you've dropped the GA snippet into more than one website, maybe you've even used its Javascript API to implement tracking at the event level.

Google Tag Manager (GTM) is a related tool, but on a higher level and thus with much more power. GTM is not a replacement for GA. Rather, it can make GA configurable without changing anything in the application's code base (and much more beyond, see below).

Only prefer GTM if the customer requests it, or if he is updating his tracking r…

Using the Ruby block shortcut with arguments

Ruby has this handy block shortcut map(&:to_i) for map { |x| x.to_i }. However, it is limited to argument-less method invocations.

To call a method with an argument, you usually need to use the full block form. A common case is retrieving values from a list of hashes (imagine using a JSON API):

users = [ { name: 'Dominik', color: 'blue' }, { name: 'Stefan', color: 'red'} ]
names = users.collect do |user|

But with a little extension, you can do better.

Block shortcut with arguments

By defining `Symbol#c…


Stretching an HTML page to full height

This card existed before, but was outdated due to browser implementation changes. The information below is validated for the current list of browsers we support.

By default your html and body elements are only as high as the actual page content. If you only have two lines of text in your page, your html and body elements will only be around 40 pixels high, regardless of the size of your browser window.

You might be surprised by this, since setting a background on either html and body does cover the enti…


Rails route namespacing (in different flavors)

TL;DR There are three dimensions you can control when scoping routes:

scope module: 'module', path: 'path', as: 'as' do
  resources :examples, only: :index

=> Path Helpers: as_examples_path and as_examples_url
=> URLs: /path/examples
=> Controller module: Module::ExamplesController and views location: app/views/module/examples/

Changing URLs only

When you want to namespace some paths but leave the corresponding controllers and url helpers unaffected, you can use the scope method like follows:

scope path…


When you want to format only line breaks, you probably do not want simple_format

For outputting a given String in HTML, you mostly want to replace line breaks with <br> or <p> tags.
You can use simple_format, but it has side effects like keeping some HTML.

If you only care about line breaks, you might be better off using a small, specialized helper method:

def format_linebreaks(text)
  safe_text = h(text)
  paragraphs = split_paragraphs(safe_text).map(&:html_safe)

  html = ''.html_safe
  paragraphs.each do |paragraph|
    html << content_tag(:p, paragraph)
  end    ...

Haml: Prefixing a group of attributes

Haml lets you prefix a group of attributes by wrapping them in a hash. This is only possible with the {} attribute syntax, not with the () attribute syntax.

Example: HTML5 data attributes

HTML5 allows you to use arbitrary attributes like data-method and data-confirm. You can prefix a group of data- attributes like this:

%a{href: '/path', data: { method: 'delete', confirm: 'Really delete?' }} Label

This compiles to:

<a data-confirm='Really delete?' data-method='delete' href='/path'>Label</a>



Designing HTML email

The 90s are calling: they want their tables back. Unfortunately, you'll need them all for laying out your HTML emails. (It is really that bad.)

Email client HTML rendering is way more scattered than browser HTML. While you might have a pretty good understanding of what features and patterns you can use to support all major browsers, I doubt anyone masters this craft for HTML email clients.

The only way to ensure your email looks good (acceptable, at least) in all mail clients, is to check it. Litmus is your go-to solu…

Auto-destruct in 16 days

Updated: Unpoly: Loading large libraries on-demand

Rails asset pipeline

As in newer Rails all assets are precompiled and the path above /huge-lib.js will at least not exist in production. Here is our preferred way to solve this:

1. Copy the large library to your vendor folder e.g. vendor/asset-libs/huge-lib/huge-lib.js

2. Create a new file e.g. app/assets/javascripts/huge-lib.js with the following content:

//= require huge-lib.js

3. Allow this file to be precompi…


Lazy-loading images

Since images are magnitudes larger in file size than text (HTML, CSS, Javascript) is, loading the images of a large web page takes a significant amount of the total load time. When your internet connection is good, this is usually not an issue. However, users with limited bandwidth (i.e. on mobile) need to mine their data budget better.

One popular strategy to improve the website performance is to not load images until they enter the viewport – aka "lazy-loading images".

General Issues

  • Crawlers do not execute JavaScript (generally sp…

Capistrano task to tail remote application logs of multiple servers

When your application is running on a multi-server setup, application logs are stored per server (unless you choose a centralized logging solution).
Here is a Capistrano task that connects to all servers and prints logs to your terminal like this:

$ cap production app:logs
00:00 app:logs
      01 tail -n0 -F /var/www/your-application/shared/log/production.log | while read line; do echo "$(hostname): $line"; done
      01 app01-prod: Started GET "/sign_in" for at 2018-04-26 11:28:19 +0200
      01 app01-prod: Proc...

Redirecting responses for PATCH or DELETE will not redirect with GET

Redirect responses to PATCH and DELETE requests will be followed with PATCH or DELETE. Redirect responses to GET and POST will be followed with a GET.
The Rails form_for helper will use a workaround to send POST requests with a _method param to avoid this issue for PATCH/DELETE.

If you make requests yourself, watch out for the following behavior.

When you make an AJAX request PATCH /foo and the /foo action redirects to /bar, browsers will request PATCH /bar. You probably expected the second request to be…


ActiveRecord: When aggregating nested children, always exclude children marked for destruction

When your model is using a callback like before_save or before_validation to calculate an aggregated value from its children, it needs to skip those children that are #marked_for_destruction?. Otherwise you will include children that have been ticked for deletion in a nested form.

Wrong way

class Invoice
  has_many :invoice_items
  accepts_nested_attributes_for :invoice_items, :allow_destroy => true # the critical code 1/2
  before_save :calculate_and_store_amount                              # the critical code 2/...

Heads up: Rails offers two similar means for text truncation

Rails defines a #truncate helper as well as a method String#truncate.

= truncate("my string", length: 5)
= "my string".truncate(5)

Both are really similar; in fact, the helper invokes the method and improves it with two niceties: support for passing a block (which could e.g. render a "read on" link), and html_safe knowledge.

Prefer the truncate() helper

The method knows nothing about html_safe and will always return an unsafe string. FWIW, an HTML string may easily become invalid when truncated, e.g. when a closing ta…


How to make your application assets cachable in Rails

Note: Modern Rails has two build pipelines, the asset pipeline (or "Sprockets") and Webpacker. The principles below apply for both, but the examples shown are for Sprockets.

Every page in your application uses many assets, such as images, javascripts and stylesheets. Without your intervention, the browser will request these assets again and again on every request. There is no magic in Rails that gives you automatic caching for assets. In fact, if you haven't been paying attention to this, your application is probabl…


Rails: Including HTML in your i18n locales

TL;DR Append your locale keys with _html to have them marked as html_safe.

When you're localizing a Rails application, sometimes there is this urge to include a little HTML. Be it some localized link, or a set of <em> tags, you'd like to have it included in the locale file. Example:

# Locale file
text: 'Please visit our corporate website to learn more about the corporation.'


= t('.text')

Desired output

Please visit our <a href="https://w…


Rails asset pipeline: Why things break in production and what precompilation does to your assets

When you work with a Rails 3.1+ application, you will be working with the asset pipeline. The asset pipeline is awesome until you deploy. Then it will be less so if you haven't done everything as the pipeline expected it from you.

The problem

When using the asset pipeline your assets (images, javascripts, stylesheets, fonts) live in folders inside app:


With the asset p…


simple_format does not escape HTML tags

simple_format ignores Rails' XSS protection. Even when called with an unsafe string, HTML characters will not be escaped or stripped!

Instead simple_format has a whitelist of tags it allows. These are:

=> #<Set: {"small", "dfn", "sup", "sub", "pre", "blockquote", "ins", "ul", "var", "samp", "del", "h6", "h5", "h4", "h3", "h2", "h1", "span", "br", "hr", "em", "address", "img", "kbd", "tt", "a", "acronym", "ab...
This website uses cookies to improve usability and analyze traffic.
Accept or learn more