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

How to fix routing error when using concerns in Rails up to 3.2.22.1

tl;dr

  • Don't write resources :people, :concerns => :trashable

  • Write

    resources :people do
      concerns :trashable
    end
    

Why

Writing a controller spec I encountered this error:

Failure/Error: get :index
ActionController::RoutingError:
  No route matches {:controller=>"people"}

caused by this route definition

resources :people, :concerns => :trashable

which renders strange routes:

      trash_person PUT    /people/:id/trash(.:format)             people#check {:concerns=>:trashable}
          ...

nginx: How to drop connections for a location

If you want to configure your nginx to drop connections to a specific location, you can do so by responding with HTTP response code 444.

Status 444 is a non-standard response code that nginx will interpret as "drop connection".

Example:

server {
  listen 127.0.0.1;
  
  location /api/ {
    return 444;
  }
}

An example use case is reverse-proxying with nginx and simulating a route that drops connections.

Rails route namespacing (in different flavors)

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

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

as → prefixes path helpers: path_helper_name_examples_path and path_helper_name_examples_url
path → prefixes URL segments: /url_prefix/examples
module → nests the controller: controller Module::ExamplesController, found at app/controllers/module/examples_controller.rb with views in app/views/module/examples/.

These options work with ...

Create and send any HTTP request using the Postman request builder

Talking with APIs makes more fun using Postman. As an alternative you can also use command line tools like cURL.

Image

snap install postman

How does it help me?

  • Editing multiline JSON bodies is much more comfortable than in the terminal
  • Saving named requests in a collection (can be shared with others)
  • Syntax highlighting when writing JSON bodies
  • History with all my requests
  • Multiple environments
  • Cookie manager

HTTP 302 redirects for PATCH or DELETE will not redirect with GET

A HTTP 302 Found redirect 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 requ...

Centering with CSS vertically and horizontally (all options overview)

There are a million ways to center <div>s or text in CSS, horizontally or vertically. All the ways are unsatisfying in their own unique way, or have restrictions regarding browser support, element sizes, etc.

Here are two great resources for finding the best way of aligning something given your use case and browser support requirements:

How to center in CSS

A long form that lets you define your use case and browser support requirements, then shows you the preferred way of aligning.

[Centering CSS: A co...

Geordi 1.3 released

Changes:

  • Geordi is now (partially) tested with Cucumber. Yay!
  • geordi cucumber supports a new @solo tag. Scenarios tagged with @solo will be excluded from parallel runs, and run sequentially in a second run
  • Support for Capistrano 2 AND 3 (will deploy without :migrations on Capistrano 3)
  • Now requires a .firefox-version file to set up a test firefox. By default now uses the system Firefox/a test Chrome/whatever and doesn't print warnings any more.
  • geordi deploy --no-migrations (aliased -M): Deploy with `cap ...

Marvel | Elastic

Dashboard (Marvel Kibana) and query tool (Marvel Sense) for Elasticsearch.

Once installed you can access Kibana and Sense at these local URLs: