Rails: Verify the CSRF token

Rails uses a CSRF token in forms and AJAX requests to verify a user request. Internally it compares the injected CSRF token of the form data with the CSRF token in the encrypted user session. To prevent SSL BREACH attacks, the CSRF token from the form data is masked.

To better debug issues, when these tokens do not match, it is useful to unmask the CSRF token from the form da...

A collection of useful design resources for developers

This collection contains some useful design resources for developers. Many of them were mentioned in the Refactoring UI tutorials.

Tutorials

Checking database size by row count

As an application exists, data accumulates. While you'll be loosely monitoring the main models' record count, some supportive database tables may grow unnoticed.

To get a quick overview of database table sizes, you can view the row count like this:

PostgreSQL

SELECT schemaname,relname,n_live_tup 
FROM pg_stat_user_tables 
ORDER BY n_live_tup DESC
LIMIT 12;

 schemaname |                    relname                     | n_live_tup 
------------+------------------------------------------------+------------
 public     | images...

Rails: Invoking a view helper from the console

There are a few ways to access view helpers from the Rails console. The easiest way is the helper shortcut:

helper.translate 'i18n.string'
helper.your_helper_method

If the desired helper renders a view template, you need this setup:

view_paths = Rails::Application::Configuration.new(Rails.root).paths["app/views"]
av_helper = ActionView::Base.new(view_paths).extend YourHelperModule

av_helper.your_helper_method

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

You can use constraints in your routes.rb to avoid getting 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' }

Note: You can also avoid this error through [format constraints in your controllers](/makandra...

Controlling how your website appears on social media feeds

When a user shares your content, a snippet with title, image, link and description appears in her timeline. By default social networks will use the window title, the first image, the current URL and some random text snippet for this purpose. This is often not what you want.

Luckily Facebook, Twitter, etc. lets you control how your content appears in the activity streams. They even have agreed on a common format to do this: OpenGraph <meta> tags that go into your HTML's <head>:

<meta property="og:url" content="http://start.m...

Unpoly: Automatically show the full better_errors page when Rails raises an error

When an AJAX request raises an exception on the server, Rails will show a minimal error page with only basic information. Because all Unpoly updates work using AJAX requests, you won't get the more detailled better_errors page with the interactive REPL.

Below is an event listener that automatically repeats the request as a full-page load if your development error shows an error page. This means you get...

Jasmine: using async/await to write nice asynchronous specs

Jasmine has long standing support for writing asynchronous specs. In days gone by we used the done callback to achieve this, but these days it is possible to write much more readable specs.

Async specs

As a first example, say we want to check that some form disables the submit button while working.

// bad (how we used to do it)

beforeEach(() => {
  this.form = setupMyForm()
  this.submitButton = findTheSubmitButton()
})

it('disables the submit button while working', (done) => {
  expect(this.submitButton.disabled).toBe(false)
...

Adding Jasmine JavaScript specs to a Webpack(er) project

The goal is to get Jasmine specs running in a Rails project using Webpacker, with the browser based test runner. Should be easily adaptable to a pure Webpack setup.

Image

Step 1: Install Jasmine

yarn add jasmine-core

Step 2: Add two separate packs

Since we do not want to mix Jasmine into our regular Javascript, we will create two additional packs. The first only contains Jasmine and the test runner. The second will contain our normal application code and the specs themselves.

We cannot...

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

How to recognize CVE-2019-5418

If you get requests with values for formats like this:

{:locale=>[:de], :formats=>["../../../../../../../../../../etc/services{{"], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :haml]}

or fails like this:

Invalid query parameters: invalid %-encoding (../../../../../../../../../etc/passwd%%0000.html)

Someone tries to exploit CVE-2019-5418.
If you use the latest Rails (or latest Rails LTS) you're...

Heads up: Capybara 3's text matchers no longer squish whitespace by default

Until Capybara 2, node finders that accept a text option were able to find nodes based on rendered text, even if it spans over multiple elements in the HTML. Imagine a page that includes this HTML:

<div class='haystack'>
  Hi!
  <br>
  Try to match me.
</div>

Even though the text is separated by a <br> tag in the HTML, it is matched until Capybara 2 which used to "squish" text prior to the comparison.

# Capyabara 1 or 2
page.find(...

Webpack: Automatically generating an icon font from .svg files

Over the years we have tried several solution to have vector icons in our applications. There are many ways to achieve this, from SVGs inlined into the HTML, SVGs inlined in CSS, JavaScript-based solutions, to icon fonts.

Out of all these options, the tried and true icon font seems to have the most advantages, since

  • icon fonts are supported everywhere
  • they perform well and require no JavaScript at all
  • their icons align nicely with text
  • their icons automatically inherit color and size of the surrounding text

The big issue used to b...

Capybara: Testing file downloads

Download buttons can be difficult to test, especially with Selenium. Depending on browser, user settings and response headers, one of three things can happen:

  • The browser shows a "Save as..." dialog. Since it is a modal dialog, we can no longer communicate with the browser through Selenium.
  • The browser automatically downloads the file without prompting the user. For the test it looks like nothing has happened.
  • The browser shows a binary document in its own window, like a PDF. Capybara/Selenium freaks out because there is no HTML docum...

SameSite cookies

TL;DR Most web applications do not require action on this. SameSite=None (old browser default) will continue to work, and SameSite=Lax (new Chrome default, gradually rolled out) is an even better default for cookies. Set SameSite=Strict only for extra security in special cases (see below). If your application is rendered in an iframe (e.g. a video player or some news stream), you need to configure its relevant cookies as SameSite=None.


The SameSite cookie attribute targets **c...

Self-expiring URLs with Apache

When delivering non-public uploaded files (images, documents etc), one has to decide whether and how to do authorization. The usual approaches are:

  • Using send_file with a regular controller. This is secure, but potentially slow, especially for large collections of images.
  • Using unguessable URLs. This is fast (because Apache can deliver assets without going through Rails), but less secure.

When going with the "unguessable URL" approach, it is possible to somewhat increase security by using expiring URLs. The idea is to encode the expi...

Migration from the Asset Pipeline to Webpacker

This is a short overview of things that are required to upgrade a project from the Asset Pipeline to Webpacker. Expect this upgrade to take a few days even the diff is quite small afterwards.

Preparations

1. Find all libraries that are bundled with the asset pipeline. You can check the application.js and the application.css for require and import statements. The source of a library is most often a gem or a vendor directory.
2. Find an working example for each library in the application and write it down.
3. Find out the ver...

ActionMailer: Previewing mails directly in your email client

In Rails, we usually have a mailer setup like this:

class MyMailer < ActionMailer::Base

  def newsletter
    mail to: 'receiver@host.tld',
      from: 'sender@host.tld',
      subject: 'My mail'
  end

end

If you want to preview your mail in the browser, you can use the Action Mailer Preview. To inspect the mail directly in your email client, just create an .eml file and open it with your client:

mail = MyMailer.newsletter
Fil...

HTML emails with inline stylesheets and webpacker

Many mail clients do not support external style sheets. Some even require all styling inline, which means you'll have to do your styling inline. For Rails applications, you can use Roadie or premailer, which lets you keep your well-structured CSS files and do the inlining for you.

See Designing HTML email

Since Roadie is now in passive maintenance mode, we go with premailer:

Include premailer in your Gemfile:

gem 'premailer-ra...

Using local fonts with Webpack / Webpacker

When we want to use our own (or bought) fonts in an application with Webpack(er), we have two options. We can

  • put the fonts directly into your Webpack's assets folder or
  • write an npm package with an own sass file that can be imported from the Webpack manifest.

Load fonts from your assets folder

The first option turns out to be straightforward: Import the stylesheets in the index.js of the pack you're using:

// webpack_source_path/application/index.js

import './stylesheets/reset'
import...

Rails: Passing array values to tag helpers like link_to

From at least Rails 4, the ActionView tag helper turns Array values of HTML options into a single space-separated string.
This means you can pass an array to :class options:

extra_classes = %w[one two]

= link_to 'Dashboard', root_path, class: ['btn', 'btn-primary', *extra_classes]
=> <a href="/" class="btn btn-primary one two">Dashboad</a>

= content_tag 'div', 'Hello World', class: %w[alert alert-info]
=> <div class="alert alert-info">Hello World</div>...