Popular mistakes when using nested forms

Here are some popular mistakes when using nested forms:

  • You are using fields_for instead of form.fields_for.
  • You forgot to use accepts_nested_attributes in the containing model. Rails won't complain, but nothing will work. In particular, nested_form.object will be nil.
  • The :reject_if option lambda in your accepts_nested_attributes call is defined incorrectly. Raise the attributes hash given to your :reject_if lambda to see if it looks like you expect.
  • If you are nesting forms into nested forms, each model involved ne...

Be very careful with 301 and 308 redirects

Browsers support different types of redirects.

Be very careful with these status codes:

  • 301 Moved Permanently
  • 308 Permanent Redirect

Most browsers seem to cache these redirects forever, unless you set different Cache-Control headers. If you don't have any cache control headers, you can never change them without forcing users to empty their cache.

Note

By default Rails sends a ...

Generating test images on the fly via JavaScript or Ruby

When you need test images, instead of using services like lorempixel or placehold.it you may generate test images yourself.

Here we build a simple SVG image and wrap it into a data: URI. All browsers support SVG, and you can easily adjust it yourself.
Simply set it as an image's src attribute.

JavaScript

Simple solution in modern JavaScript, e.g. for use in the client's browser:

function svgUri(text) {
  let svg = `
    <svg wid...

Use <input type="number"> for numeric form fields

Any form fields where users enter numbers should be an <input type="number">.

Numeric inputs have several benefits over <input type="text">:

  • On mobile or tablet devices, number fields show a special virtual keyboard that shows mostly digit buttons.
  • Decimal values will be formatted using the user's language settings.
    For example, German users will see 1,23 for <input type="number" value="1.23">.
  • Values in the JavaScript API or when submitting forms to the server will always use a point as decimal separator (i.e. "1.23" eve...

ActiveRecord: String and text fields should always validate their length

If you have a :string or :text field, you should pair it with a model validation that restricts its length.

There are two motivations for this:

  • In modern Rails, database types :string and :text no longer have a relevant size limit. Without a validation a malicious user can quickly exhaust the hard drive of your database server.
  • In legacy Rails (or database schemas migrated from legacy Rails), database types :string and :text had a database-side length constraint. When the user enters a longer string, the ActiveRecord valida...

open-next-failure: An alias to speed up test debugging

Getting an entire test suite green can be a tedious task which involves frequent switches between the CLI that is running tests back to the IDE where its cause can be fixed.

The following bash aliases helped me speed up that process:

alias show-next-failure="bundle exec rspec --next-failure"
alias open-next-failure="show-next-failure || show-next-failure --format json  | jq -r '.examples[0]' | jq '\"--line \" + (.line_number|tostring) + \" \" + .file_path' | xargs echo | xargs rubymine"

There is a lot going on above but the gist...

How to make Webpacker compile once for parallel tests, and only if necessary

Webpack is the future. We're using it in our latest Rails applications.

For tests, we want to compile assets like for production.
For parallel tests, we want to avoid 8 workers compiling the same files at the same time.
When assets did not change, we do not want to spend time compiling them.

Here is our solution for all that.

Its concept should work for all test suites.

Copy the following to config/initializers/webpacker_compile_once.rb. It will patch Webpacker, but only for the test environment:

# Avoid hardcoded asset host...

How Rails chooses error pages (404, 500, ...) for exceptions

When your controller action raises an unhandled exception, Rails will look at the exception's class and choose an appropriate HTTP status code and error page for the response.

For instance, an ActiveRecord::RecordNotFound will cause Rails to render a red "The page you were looking for doesn't exist" with a status code of "404" (not found).

The mapping from exception classes to error types is a hash in Rails.configuration.action_dispatch.rescue_responses. The...

Devise: Invalidating all sessions for a user

Background information about session storage in Rails

Rails has a default mechanism to store the session in the CookieStore. This is a cookie which holds the entire user session hash in the browser. This cookie is serialized, encoded with base64, and signed.

How Devise handles authentication

Devise uses this CookieStore. To track a users session, a salt is stored in the session ...

Capistrano task to edit staging / production credentials

When using Rails credentials, you will edit the encrypted credentials for staging or production environments from time to time. To do that you need the secret key which should only live on the servers.

Do not download these key files to your local dev environment. They are sensitive and must not be stored on your machine.

Instead, put the attached capistrano task into lib/capistrano/tasks/ of your application. It expects environment specific keys to live in :shared_path/config/credentials/:stage.key. If you have a single master.key...

Test your application's e-mail spam scoring with mail-tester.com

You can use mail-tester.com to check your application's e-mails for issues that might cause e-mails to be classified as spam.

They provide a one-time e-mail addresses that you can use to sign up etc. You can then check for scoring results of SpamAssassin and other potential issues.
You don't need to hit 10/10. Something around 9/10 is perfectly fine.

Note:

  • For password-protected staging sites you will get an error for links that can not be resolved. This is fine, simply check production once available.
  • ...

Upgrade guide for moving a Rails app from Webpack 3 to Webpack 4

Webpacker is Rails' way of integrating Webpack, and version 4 has been released just a few days ago, allowing us to use Webpack 4.

I successfully upgraded an existing real-world Webpack 3 application. Below are notes on everything that I encountered.
Note that we prefer not using the Rails asset pipeline at all and serving all assets through Webpack for the sake of consistency.

Preparations

  • Remove version locks in Gemfile for webpacker
  • Remove version locks in package.json for webpack and webpack-dev-server
  • Install by ca...

PSA: Be super careful with complex `eager_load` or `includes` queries

TLDR

Using .includes or .eager_load with 1-n associations is dangerous. Always use .preload instead.

Consider the following ActiveRecord query:

BlogPost.eager_load(
  :comments
  :attachments,
).to_a

(Let's assume we only have a couple of blog posts; if you use pagination the queries will be more complicated, but the point still stands.

Looks harmless enough? It is not.

The problem

ActiveRecord will rewrite this into a query using LEFT JOINs which looks something like this:

SELECT "blog_posts...

JavaScript: Comparing objects or arrays for equality (not reference)

JavaScript has no built-in functions to compare two objects or arrays for equality of their contained values.

If your project uses Lodash or Underscore.js, you can use _.isEqual():

_.isEqual([1, 2], [2, 3]) // => false
_.isEqual([1, 2], [1, 2]) // => true

If your project already uses Unpoly you may also use up.util.isEqual() in the same way:

up.util.isEqual([1, 2], [2, 3]) // => false
up.util.isEqual([1, 2], [1, 2]) // => true

If you are wri...

Capybara: Most okayest helper to download and inspect files

Testing file download links in an end-to-end test can be painful, especially with Selenium.

The attached download_helpers.rb provides a download_link method for your Capybara tests. It returns a hash describing the download's response:

details = download_link('Download report')
details[:disposition]  # => 'attachment' or 'inline'
details[:filename]     # => 'report.txt'
details[:text]         # => file content as string
details[:content_type] # => 'text/plain'

Features

Compared to [other approaches](...

Use Time.current / Date.current / DateTime.current on projects that have a time zone

Basically, you now need to know if your project uses a "real" time zone or :local, and if config.active_record.time_zone_aware_attributes is set to false or not.

  • With time zones configured, always use .current for Time, Date, and DateTime.

    ActiveRecord attributes will be time-zoned, and .current values will be converted properly when written to the database.
    Do not use Time.now and friends. Timezone-less objects will not be converted properly when written to the database.

  • With no/local time zone use Time.now, `...

How to create giant memory leaks in AngularJS (and other client-side JavaScript)

This guide shows how to create an AngularJS application that consumes more and more memory until, eventually, the browser process crashes on your users.

Although this guide has been written for Angular 1 originally, most of the advice is relevant for all client-side JavaScript code.

How to observe memory consumption

To inspect the amount of memory consumed by your Javascripts in Chrome:

  • Open an incognito window
  • Open the page you want to inspect
  • Press Shift + ESC to see a list of Chrome processes...

Ruby: A small summary of what return, break and next means for blocks

Summary

  • Use return to return from a method. return accepts a value that will be the return value of the method call.
  • Use break to quit from a block and from the method that yielded to the block. break accepts a value that supplies the result of the expression it is “breaking” out of.
  • Use next to skip the rest of the current iteration. next accepts an argument that will be the result of that block iteration.

The following method will serve as an example in the details below:

def example
  puts yield
  puts ...

Advantages of using appname.daho.im:3000 over localhost:3000

Running rails server will start a local server that you can access via http://localhost:3000.

When you are working on multiple web apps, they will likely set cookies with generic names on localhost. This is annoying, since you will sign out your current user whenever you switch to another app.

A better way is to use our own daho.im service. All daho.im subdomains resolve to your local IP (127.0.0.1). That means you can use a different hostname for different apps, and you will stay logged in in each app:

http://foo-ap...

whenever: Installing cron jobs only for a given Rails environment or Capistrano stage

We use the whenever gem to automatically update the crontab of the servers we deploy to. By default, whenever will update all servers with a matching role (we use the :cron role ).

This card describes how to install some tasks only for a given Rails environment or for a given Capistrano stage ("deployment target").

Installing jobs only for a given Rails environment
-----------------------------------...

Middleman configuration for Rails Developers

Middleman is a static page generator that brings many of the goodies that Rails developers are used to.

Out of the box, Middleman brings Haml, Sass, helpers etc. However, it can be configured to do even better. This card is a list of improvement hints for a Rails developer.

Gemfile

Remove tzinfo-data and wdm unless you're on Windows. Add these gems:

gem 'middleman-livereload'
gem 'middleman-sprockets' # Asset pipeline!

gem 'bootstrap-sass' # If you want to use Bootstrap

gem 'byebug'

gem 'capistrano'
gem 'capistrano-mid...

RestClient / Net::HTTP: How to communicate with self-signed or misconfigured HTTPS endpoints

Occasionally, you have to talk to APIs via HTTPS that use a custom certificate or a misconfigured certificate chain (like missing an intermediate certificate).

Using RestClient will then raise RestClient::SSLCertificateNotVerified errors, or when using plain Net::HTTP:

OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed

Here is how to fix that in your application.

Important: Do not disable certificate checks for production. The interwebs are full of people say...

Faking and testing the network with WebMock

An alternative to this technique is using VCR. VCR allows you to record and replay real HTTP responses, saving you the effort to stub out request/response cycles in close details. If your tests do require close inspection of requests and responses, Webmock is still the way.


WebMock is an alternative to FakeWeb when testing code that uses the network. You sh...

Vortrag: Content Security Policy: Eine Einführung

Grundidee

CSP hat zum Ziel einen Browser-seitigen Mechanismus zu schaffen um einige Angriffe auf Webseiten zu verhindern, hauptsächlich XSS-Angriffe.

Einschub: Was ist XSS?

XSS = Cross Site Scripting. Passiert wenn ein User ungefiltertes HTML in die Webseite einfügen kann.

<div class="comment">
  Danke für den interessanten Beitrag! <script>alert('you have been hacked')</script>
</div>

Rails löst das Problem weitgehend, aber

  • Programmierfehler weiter möglich
  • manchmal Sicherheitslücken in Gems oder Rails

Lösungsid...