Git: how to work with submodules

Sometimes you might need to nest a git-project inside another git-project. The right strategy is to use submodules in this case.

How git submodules work

  • Each submodule is a own git repository
  • Once you commit changes in a submodule, the parent repository can link the new sha as its reference
  • You need to take care manually that your git submodules are up-to-date and changes in the submodules are linked in the parent repository

Add a submodule

Here is how you add a nested project inside your parent project

$ git submodule...

An intro to Javascript promises

Promises are the new way™ to express "Do this, and once you're done, do that". In contrast to callbacks, promises are easily chainable. From the readme of Q, an early implementer of the pattern:

The callback approach is called an “inversion of control”. A function that accepts a callback instead of a return value is saying, “Don’t call me, I’ll call you.”. Promises un-invert the inversion, cleanly separating the input arguments from control flow arguments. This simplifies the use and creation of APIs, p...

Amazon S3: Give a user write-access to selected buckets

There's no user interface to give an AWS IAM user read/write access to a selected list of S3 buckets.

Instead you need to attach an IAM policy like the one below to the user:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::bucket1",
                "arn:aws:s3:::bucket2"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
         ...

Ruby: __FILE__, __dir__ and symlinks

Ruby's __FILE__ keyword returns the path to the current file. On popular for this are Ruby binaries:

#!/usr/bin/env ruby
$LOAD_PATH << File.expand_path('../../lib', __FILE__)
require 'my_cli'
MyCli.run!

However, if you create a symlink to this file, this will no longer work. __FILE__ will resolve to the path of the symlink, not to its target.

One solution is to use File.realpath(__FILE__).

In Ruby 2+ you can also use this:

$LOAD_PATH << File.expand_path('../lib', __dir__)

__dir__ is simply a shortcut for `...

Middleman does not fingerprint asset paths by default

We're using Middleman for some static sites like our blog.

Despite being very similar to Rails, Middleman does not add a fingerprint hash to its asset paths by default. This means that when you write this:

<%= javascript_include_tag 'all.js' %>

... you always get the same path, regardless of the contents of all.js:

<script src='/javascripts/all.js'>

Because browsers tend to cache assets for a while, this means that users might not get your changes until their cac...

How to find out what is running on a port on a remote machine

By convention, common protocols use a defined port, like 80 for HTTP or 443 for HTTPS.

You can use nmap to find out what service is running behind a given port, and most often see some details about it. This can be helpful if servers don't offer the services you expect for some ports. If you'd like to see what ports are listing on your local machine, you might want to use ss instead of nmap.

Note that nmap's service discovery may trigger several requests.

Example

When using nmap, adding the -A switch will ...

Building web applications: Beyond the happy path

When building a web application, one is tempted to claim it "done" too early. Make sure you check this list.

Different screen sizes and browsers

Desktops, tablets and mobile devices have all different screen resolutions. Does your design work on each of them?

  • Choose which browsers to support. Make sure the page looks OK, is usable and working in these browsers.
  • Use @media queries to build a responsive design
    • If you do not suppo...

Using Google Analytics with Unpoly

The default Google Analytics might not work as expected with your Unpoly app. This is because your app only has a single page load when the user begins her session. After that only fragments are updated and the <script> tag that sends the page view to Google Analytics is probably never evaluated again.

Luckily you can fix this.

Simple mode: You just want to track all the page views

Embed your Google Analytics code as always.

Now add the following code snippet:...

You can implement basic object-fit behavior with background images

So you want to use object-fit, but you also need to support Internet Explorer.

One option is to use lazysizes as a kinda-polyfill. Another option is to implement the requirement with background-size: contain, and background-size: cover, which is supported in IE9+.

E.g. to make an image cover a 100x100 px² area, cropping the image when nece...

request_store: Per-request global storage for your Rails app

Ever needed to use a global variable in Rails? Ugh, that's the worst. If you need global state, you've probably reached for Thread.current.

When you're using Thread.current, you must make sure you're cleaning up after yourself. Else, values stored in one request may be available to the next (depending on your server). request_store wipes all data when a request ends and makes per-request global storage a no-brainer. Internally, it's using Thread.current with a Hash in a simple middleware.

Example: Remembering all currently a...

HAML 4+ expands nested element attributes

As you may know, HAML expands data attributes that are given as a hash:

%div{ data: { count: 3 } }
# results in:
<div data-count="3"></div>

However, this also works for any other hash attribute. Consider an Angular directive or an Unpoly compiler that is configured by several attributes. Usually you'd prefix them with the directive/compiler name so it gets clear where the attribute belongs. With HAML, this is easy to build:

%...

Tasks, microtasks, queues and schedules - JakeArchibald.com

The way that Javascript schedules timeouts and promise callbacks is more complicated than you think. This can be the reason why callbacks are not executed in the order that they are queued.

Please read this article!


This is an extract of the example in the article which demonstrates the execution order of tasks and microtasks.

console.log('script start');

setTimeout(function() {
  console.log('setTimeout');
}, 0);

Promise.resolve().then(function() {
  console.log('promise1');
}).then(function() {
  console.log('promise2');
})...

Dynamically uploading files to Rails with jQuery File Upload

Say we want …

  • to create a Gallery that has a name and has_many :images, which in turn have a caption
  • to offer the user a single form to create a gallery with any number of images
  • immediate uploads with a progress bar per image
  • a snappy UI

Enter jQuery File Upload. It's a mature library that can do the job frontend-wise. On the server, we'll use Carrierwave, because it's capable of caching images.

(FYI, [here's how to do the u...

UI Sortable on table rows with dynamic height

UI sortable helps reordering items with drag 'n drop. It works quite fine.

Proven configuration for sorting table rows

When invoking the plugin, you may pass several options. This set is working fine with table rows:

$tbody.sortable # Invoke on TBODY when ordering tables
  axis: 'y' # Restrict drag direction to "vertically"
  cancel: 'tr:first-child:last-child, input' # Disable sorting a single tr to prevent jumpy table headers
  containment: 'parent' # Only drag within this container
  placehol...

Preloading images with CSS

Sometimes you want to preload images that you will be using later. E.g. if hovering over a an area changes its background image, the new image should be preloaded. If you only load it once the user starts hovering, there will be a delay until the background image flips.

The attached article explains how to preload images with only CSS. No Javascript required.

The gist is:

.element:after {
  content: url(img01.jpg) url(img02.jpg) url(img03.jpg);
  display: none;
}

How to: Client-side language detection

When you have a localized website, you may want to redirect users to their preferred language when they visit the root path.
Here is how to do it without a server-side component (like a Rails application).

  • Use JavaScript's navigator.language (real browsers and IE11+) and navigator.userLanguage (old IEs).
  • Use a <meta> refresh as fallback
  • Provide buttons for paranoid users that disabled JavaScript and meta refreshs.

JavaScript

The following JavaScript will try to auto-detect a user's preferred language.

It understands string...

thoughtbot/fake_stripe: A Stripe fake so that you can avoid hitting Stripe servers in tests.

fake_stripe spins up a local server that acts like Stripe’s and also serves a fake version of Stripe.js, Stripe’s JavaScript library that allows you to collect your customers’ payment information without ever having it touch your servers. It spins up when you run your feature specs, so that you can test your purchase flow without hitting Stripe’s servers or making any external HTTP requests.

We've also had tests actually hitting the testing sandbox of Stripe, which worked OK most of the time (can be flakey).

How to preview an image before uploading it

When building a form with a file select field, you may want to offer your users a live preview before they upload the file to the server.

HTML5 via jQuery

Luckily, HTML5 has simple support for this. Just create an object URL and set it on an <img> tag's src attribute:

$('img').attr('src', URL.createObjectURL(this.files[0]))

Unpoly Compiler

As an Unpoly compiler, it looks like this:

up.compiler '[image_p...

VCR: An OAuth-compatible request matcher

OAuth requires a set of params to be carried along requests, among which a nonce. Some libraries pass these along as headers, some as query parameters. All fine.

When you're using VCR, the latter case is an issue. By default, requests are matched on method and URI. However, no request URI will equal another when they include a nonce. You won't be able to match these requests with VCR.

Solution

Obviously you need to...

Reading and writing cookies in JavaScript

You can use JavaScript to get or set cookie values on the client.

Using the vanilla JavaScript API

In JavaScript, document.cookie is an accessor to all cookies on the current site. It looks like a String, but its setter is actually more powerful.

When setting cookies this way, remember to set the path=/ option.

Reading cookies

A result may look like this:

hello=universe; foo=bar

This means that there are 2 cookies: "hello" with value "universe", and "foo" with value "bar...

jQuery promises: done() and then() are not the same

jQuery's deferred objects behave somewhat like standard promises, but not really.

One of many subtle differences is that there are two ways to chain callbacks to an async functions.

The first one is done, which only exists in jQuery:

$.ajax('/foo').done(function(html) {
  console.debug("The server responded with %s", html);
});

There is also then, which all promise libraries have:

$.ajax('/foo').then(function(html) {
  console.debug("The server resp...

Analyse short links

Sometimes you might want to check a short link for it's destination before clicking on it. Additional you get information about the redirects.

Use the magic + at the end of the short url!

Google:
https://goo.gl/TXe0Kx => https://goo.gl/TXe0Kx+
Since the original publication of this post, Google's URL shortening service goo.gl has been discontinued.

Bitly:
http://bit.ly/1VRwNVt => [http://bit.ly/1VRwNVt+](http:/...

Manually uploading files via AJAX

To upload a file via AJAX (e.g. from an <input type='file'>) you need to wrap your params in a FormData object.

You can initialize a FormData using the contents of a form:

var form = document.querySelector('form.my-form') // Find the <form> element
var formData = new FormData(form); // Wrap form contents

Or you can construct it manually, param by param:

var fileInput = document.querySelector('form input[type=file]');
var attachment = fileInput.files[0];

var f...

Heads up: Angular may break links to the current URL (e.g. when using ngInclude)

Angular's location provider stalls links to the current URL, i.e. window.location. As soon as the $location service is activated in an Angular app, it will intercept links. The click event handler is registered in $LocationProvider.$get().

The motivation is reasonable, as they want to keep the Browser history clean when Angular is controlling it. However, when Angular is NOT controlling your interaction with the browser history (i.e. you're just using Angular as JS sugar on your page), Angular will create the above issue as soon as you u...