Prefer using Dir.mktmpdir when dealing with temporary directories in Ruby

Ruby's standard library includes a class for creating temporary directories. Similar to Tempfile it creates a unique directory name.

Note:

  • You need to use a block or take care of the cleanup manually
  • You can create a prefix and suffix e.g. Dir.mktmpdir(['foo', 'bar']) => /tmp/foo20220912-14561-3g93n1bar
  • You can choose a different base directory than Dir.tmpdir e.g. `Dir.mktmpdir('foo', Rails.root.join('tmp')) => /home/user/rails_example/tmp/foo20220912-14...

How to get the git history of a file that does not exist anymore

If you want to see the git history of a project file, that doesn't exist anymore, the normal git log <path_to_file> won't work. You have to add certain flags to make it work:

git log --all --full-history -- <path_to_file>

Rails: Comparison of Dates - before? and after?

tl;dr

Since Rails 6+ you can use before? and after? to check if a date/time is before or after another date/time.

Example

christmas = Date.parse('24.12.2022')
date_of_buying_a_gift = Date.parse('12.12.2022')

date_of_buying_a_gift.before?(christmas)
# => true
# Now you are well prepared for Christmas!! ;)

date_of_buying_a_gift = Date.parse('26.12.2022')

date_of_buying_a_gift.after?(christmas)
# => true
# Now you are too late for christmas! :(

Hint

If you want to check if a date/time is between to ot...

Statistics and Reports on Web Performance Optimization

Case studies and experiments demonstrating the impact of web performance optimization (WPO) on user experience and business metrics.

Careful: `fresh_when last_modified: ...` without an object does not generate an E-Tag

To allow HTTP 304 responses, Rails offers the fresh_when method for controllers.

The most common way is to pass an ActiveRecord instance or scope, and fresh_when will set fitting E-Tag and Last-Modified headers for you. For scopes, an extra query is sent to the database.

fresh_when @users

If you do not want that magic to happen, e.g. because your scope is expens...

Ruby and Rails: Debugging a Memory Leak

A memory leak is an unintentional, uncontrolled, and unending increase in memory usage. No matter how small, eventually, a leak will cause your process to run out of memory and crash.

If you have learned about a memory leak, looking at the number of Ruby objects by type can help you track it down:

> pp ObjectSpace.count_objects
{:TOTAL=>77855,
 :FREE=>4526,
 :T_OBJECT=>373,
 :T_CLASS=>708,
 :T_MODULE=>44,
 :T_FLOAT=>4,
 :T_STRING=>65685,
 :T_REGEXP=>137,
 :T_ARRAY=>984,
 :T_HASH=>87,
 :T_STRUCT=>12,
 :T_BIGNUM=>2,
 :T_FILE=>3,
 :T_D...

Rails: Custom validator for "only one of these" (XOR) presence validation

For Rails models where only one of multiple attributes may be filled out at the same time, there is no built-in validation.

I've seen different solutions in the wild, each with different downsides:

  • Private method referenced via validate: works, but is barely portable and clutters the model.
  • Multiple presence validations with "if other is blank" each: looks pretty, but is incorrect as it allows both values to be filled in; also the error messages for a blank record are misleading.

Here is a third option: Write a custom validator to ...

JSON APIs: Default design for common features

When you build a JSON API you need to come up with a style to represent attributes, pagination, errors or including associated objects. Instead of reinventing the wheel, you may reuse successful API designs.

JSON API

JSON:API specifies common features found in most JSON APIs, like pagination, ordering and nested resources. The spec looks very similar to how one would build an API with Rails and uses similar patterns. Even if you don't plan on supporting the whole spec, it can still make sense to know how th...

Converting SVG to other vector formats without Inkscape

If you need to convert an SVG source to PS or EPS, the most common suggestion on the interwebs is to use Inkscape from the commandline.
Inkscape is a fairly resource-heavy tool with lots of dependencies. A great alternative for converting is CairoSVG.

CairoSVG is available on most Linux distros through their package management systems, e.g. apt install cairosvg on Ubuntu.
It has few dependencies (most importantly Python 3 and some related packages, but really not much)...

How to use a local gem in your Gemfile

You can use local copies of gems in your Gemfile like this:

gem 'spreewald', path: '~/gems/spreewald'

As soon as you have bundled your project with the local copy of the gem, all code changes in the copy will be available on your project. So you can for example set a debugger or add console output in the gem and use it from your project.
If you checked out the gem with your versioning tool, you can easily reset your changes afterwards or make a pull request for the gem if you improved it.

Don't commit a Gemfile with local path...

Helper methods - RSpec Core

You can define methods in any example group using Ruby's def keyword or define_method method. These helper methods are exposed to examples in the group in which they are defined and groups nested within that group, but not parent or sibling groups.

How to bulk-unwatch many repositories on Github

To easily opt out of notifications for a large number of Github repositories, go to https://github.com/watching.

A simpler default controller implementation

Rails has always included a scaffold script that generates a default controller implementation for you. Unfortunately that generated controller is unnecessarily verbose.

When we take over Rails projects from other teams, we often find that controllers are the unloved child, where annoying glue code has been paved over and over again, negotiating between request and model using implicit and convoluted protocols.

We prefer a different approach. We believe that among all the classes in a Rails project, controllers are some of the hardest to...

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

Defining new elements for your HTML document

Browsers come with a set of built-in elements like <p> or <input>. When we need a new component not covered by that, we often build it from <div> and <span> tags. An alternative is to introduce a new element, like <my-element>.

When a browser encounters an unknown element like <my-element>, the browser will proceed to render <my-element>'s children. The visual rendering of your page will not be affected.

If you care about their HTML being valid, your new element should contain a dash character (-) to mark it as a *custom el...

Defining and calling lambdas or procs (Ruby)

There are different ways to define a lambda or proc in ruby. [*]

  1. with lambda keyword

    test = lambda do |arg|
      puts arg
    end
    
  2. with the lambda literal -> (since Ruby 1.9.1)

    test = ->(arg) do
      puts arg
    end
    
  3. with the proc keyword (which defines a lambda that does not test the given number of arguments):

    test = proc do |arg|
      puts arg
    end
    

[*] Technicalities:

  • There is only Proc. Both proc and lambda create instances of Proc (but lamb...

Updated: Git: removing feature branch on merge

  • Resolve @{-1} to actual branch name. (Happens when merging "-".)

Creating a Rails application in a single file

Greg Molnar has written a neat article about creating a single-file Rails app.
This is not meant for production use but can be useful to try things out, e.g. when hunting down a bug or embedding a Rails app into the tests of a gem.

What you do is basically:

  1. Put everything (gems, application config, database migrations, models, controllers) into a single .ru file, like app.ru.
  2. Run it via rackup app.ru. (Hint: if your file is called config.ru, you can just run `rac...

Web development: Accepting a self-signed certificate in Google Chrome

Working with a self-signed certificate is much easier, when the browser accepts it.

Google Chrome

Warnings from chrome might not be accurate

Even though the certificate is working locally, chrome might still complain that the certificate is not valid and the connection is not secure while blotting out the "https" part of the url.

Accept a specific certificate

  • Go to chrome://settings/certificates
  • Under "Authorities", click "Import"
  • Select the certificate file (.crt)
  • Check "Trust this certificate for identi...

Git: removing feature branches on merge

When working with feature branches, stale branches pile up over time. It's best to remove them right after merge, locally and on the remote, but it is a little tedious: you need to remember it, and perform the few steps manually each time.

Enter Git hooks. The folks at Liquid Light have built a little post-merge hook that will delete a feature branch on confirmation....

Debugging cucumber feature with javascript + firefox vnc

TL;DR Debugging problems with javascript errors in cucumber tests is sometimes easier in the browser. Run the test, stop at the problematic point (with Then pause from Spreewald 1.7+) and open VNC for Firefox.

Features:

Cancelling event propagation

Within an event handler, there are multiple methods to cancel event propagation, each with different semantics.

  • event.preventDefault()

    Only prevents the default browser behavior for the click, i.e. going to a different url or submitting a form.

    When invoked on a touchstart event, this also prevents mouse events like click to be triggered.

  • event.stopPropagation()

    Prevents the event from bubbling up the DOM.

  • `event.st...

Working with or without time zones in Rails applications

Rails supports time zones, but there are several pitfalls. Most importantly because Time.now and Time.current are completely different things and code from gems might use one or the other.

Especially configuring an application that cares only about one time zone is a bit tricky.

The following was tested on Rails 5.1 but should apply to Rails 4.2 as well.

Using only local time

Your life will be easier if your application does not need to support time zones. Disable them like this:

config.time_zone = 'Berlin' # Your local ...