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…


Writing a README for a Rails project

A Rails project should have a README that gives the reader a quick overview of the project. Its size will vary as projects differ in complexity, but there should always be some introductory prose for a developer to read when starting on it.


That's already the main purpose of a project README: Give a new developer a quick overview of the project. In sketching this outline, the README should notify the reader of any peculiarity he needs to know of.

Remember that in a few months, you'll be a kind of "new developer" yourse…

How to use cookies with curl

When making requests using curl, no cookies are sent or stored by default.
However, you can tell curl to re-use cookies received earlier (or forge your own cookies).

There are 2 command line switches you need to use:

  • -c will write cookies to a given file
  • -b will read cookies from a given file


The remote server sets a "foo" cookie to value "bar". We tell curl to store them to a file at /tmp/cookies using the -c switch.

$ curl -c /tmp/cookies

You may look at the file, …


Beware: Many browsers define window.event

Some browsers define window.event, which will return a copy of the "current" event. However, this is not defined by the W3C. Most importantly, Firefox does not support it, neither do recent versions of IE.

You should completely avoid accessing the global event and instead pass the event object around that the event handler receives. The easiest protection against accidentally accessing window.event is just never naming the event event, but e or evnt or so.

function brokenInFirefox() {
event.preventDefault(); // Break…


How to: Context-dependent word expansion in RubyMine

One of the many useful features of TextMate is autocompletion of words. If I were in TextMate right now, I could write "au[tab]", and it would complete it to "autocompletion". RubyMine can do this, too. When you write a word (e.g. a variable name), just hit ALT + / repeatedly and it will offer all completions for the letters you typed. This action is called Cyclic Expand Word in RubyMine / IntelliJ IDEA.

This feature keeps you from mistyping variable names, saves you keystrokes and speeds up development. ~10 keystrokes to the price …


Why your Cucumber feature loses cookies when run under Selenium or capybara-webkit

When your Cucumber feature seems to forget cookies / sessions when you run it with Selenium or capybara-webkit, check if the test travels in time like here:

Given the date is 1981-10-20
When I sign in
Then I should see "Welcome!"

What happens here is that the Rails application serving pages runs in 1984, but the process running your Firefox or Webkit still lives today. This gap of 27+ years will expire most Cookies immediately.

If all you need is to freeze the time to a date, a workaround is to travel to the future instead.

Error during Rails 5 upgrade: Environment data not found in the schema

This error is raised because your old database does not have a configured environment yet, which Rails 5 enforces.

If this error occurs while migrating your parallel test databases, make sure to update the parallel_tests gem first: current versions fix this. If you're still using Cucumber < v3, the latest version of parallel_tests will be 2.18.0.

How to find and replace empty cells in Libre Office Calc

To find and replace (CTRL + H) empty cells in Libre Office Calc you can use a regular expressions (also called "Finds an empty paragraph" in context of a spreadsheet):


It is also possible to just enter a regular expression in the search (CTRL + F), but there is no option to only search in the current selection like in the screenshot above. Use find and replace instead if needed.


CarrierWave: How to remove GIF animation

When accepting GIF images, you will also accept animated GIFs. Resizing them can be a time-consuming task and will block a Rails worker until the image is processed.

Save yourself that trouble, and simply tell ImageMagick to drop any frames but the first one.

Add the following to your uploader class:

process :remove_animation


def remove_animation
  if content_type == 'image/gif'
    manipulate! { |image| image.collapse! }

You may also define that process for specific versions only (e….

Rails: Migration helper for inserting records without using models

You should avoid using application models in your migrations. But how else would you create records in a migration?

The simplest alternative is to write plain SQL. Since INSERT statements are no pleasant write for Rubyists, here is a simple wrapper:


The helper method below takes a table name and a hash of attributes, which it inserts into the specified table. Copy it over to your migration and profit!


def insert_record(table, **attributes)


Testing regular expressions visually

Developing complex regular expressions quickly blows my mind. Here are some online regex editors that help you by highlighting matching text and capture groups:


Don't ever use the float type for database columns

Like in any language, a FLOAT will eventually corrupt data due to rounding errors.

Please use DECIMAL, which has well-defined behavior for rounding and range overflows.

Remember: LoDash syntax is a bit different from UnderscoreJS

Since we are using LoDash instead of UnderscoreJS in recent/current projects, you should keep in mind that their syntax is a bit different.


In UnderscoreJS, methods always return a value:

x = [1, 2, 2]
_.uniq(x) // => [1, 2]
_(x).uniq() // => [1, 2]

If you want to chain multiple calls, you need to start off with a _.chain, and call value() to terminate the chain.

_.chain(x).uniq().map(function(i) { return i + 10 }).reverse().value() // => [12, 11]


External contentRepeats

Create and send any HTTP request using the Postman request builder

Talking with APIs makes more fun using Postman. Otherwise you might want to read: How to send HTTP requests using cURL

Postman ist available as Chrome or Mac App.

How does it helped me?
- Editing multiline JSON bodies is much more comfortable than in the terminal
- Saving named request in a collection
- Syntax highlighting when writing JSON bodies
- History with all my request
- Multiple environments

CSS: Giving text lines a background-color (with configurable line padding and margin)

The gist is:

  • wrap the text with a span
  • use line-height for the spacing between lines ("margin")
  • use box-shadow to control the line background size ("padding")



  box-shadow: 0 0 0 10px #fff
  background-color: #fff
  box-decoration-break: clone # Fix Firefox
  line-height: 2.2

→ [jsfiddle](…

Jasmine: Expecting objects as method invocation arguments

To check if a method has been called in Jasmine, you first need to spy on it:

let spy = spyOn(window, 'alert')
expect(window.alert).toHaveBeenCalledWith('Important message')

To expect an object of a given type, pass the constructor function to jasmine.any():


To expect an oject with given key/value properties, use `jasmine.objectContaini…


Be careful when using buttons without a "type" attribute

Be careful when using buttons without a type attribute, since browsers will consider them the default submit button of a form.

Suppose you have this form:

<form action="/save">
  <input type="text" />
  <button onclick="alert('Alert!')">Alert</button>
  <button type="submit">Save</button>

If you press the enter key inside in the text input, browsers will trigger the first button and show the alert.

To fix this, add a type="button" attribute to the first button.

3447 cards