How to make Rational#to_s return strings without denominator 1 again

The way Rational#to_s works on Ruby has changed from Ruby 1.9 on. Here is how to get the old behavior back.

You may want this for things where Rationals are being used, like when subtracting Date objects from one another.

What's happening?

Converting a Rational to a String usually does something like this:

1.8.7 > Rational(2, 3).to_s
=> "2/3"
1.9.3 > Rational(2, 3).to_s
=> "2/3"
2.0.0 > Rational(2, 3).to_s
=> "2/3"

However, when you have a Rational that simplifies to an integer, you will only get a St...

Capturing signatures on a touch device

If you need to capture signatures on an IPad or similar device, you can use Thomas J Bradley's excellent Signature Pad plugin for jQuery.

To implement, just follow the steps on the Github page.

The form

If you have a model Signature with name: string, signature: text, you can use it with regular rails form like this:

- form_for @signature, :html => { :class => 'signature_form' } do |form|
  %dl
    %dt
      = form...

Careful with '||=' - it's not 'memoize'

When you do something like this in your code:

def var_value
  @var ||= some_expensive_calculation
end

Be aware that it will run some_expensive_calculation every time you call var_value if some_expensive_calculation returns nil.

This illustrates the problem:

def some_expensive_calculation
  puts "i am off shopping bits!"
  @some_expensive_calculations_result
end

When you set @some_expensive_calculations_result to nil, ||= runs some_expensive_calculation every time....

Unpoly: Testing values for presence or blankness

In Ruby on Rails, all objects have a useful blank? method. It returns true for nil but also for empty strings or empty arrays. There is also a universal method present? which returns true for all values that are not blank?.

In JavaScript you need to roll your own implementation of blank? and present?.

If your application uses [Unpoly](...

Find geocoded records that are close to a location (radius search)

When you have objects in your database that hold latitude and longitude and you want to find others that are close to given coordinates you can use the Graticule gem.

Graticule

Graticule offers several methods to compute the distance between two geo-dated objects but fetching records from the database that are within a given radius of a location is a bit trickier:

def close_destinations(latitude, longitude)
  distance_sql = Graticule::Distance::Spherical.to_sql(:latitude => l...

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

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

Putting static content on Cloudfront

We recently decided to put static content for HouseTrip.com to Amazon Cloudfront for a faster user experience. This happens fully automatically on deploy and is transparent in development. Together with a heavy use of sprites this sped up page load time quite nicely.

These are a couple of the problems you need to solve in order to do this:

  • There is no good way to invalidate Cloudfront cached assets, and Cloudfront will ignor...

How to: Use Ace editor in a Webpack project

The Ace editor is a great enhancement when you want users to supply some kind of code (HTML, JavaScript, Ruby, etc).
It offers syntax highlighting and some neat features like auto-indenting.

For Webpack 3+

Integrate as described in the documentation. For example load ace Editor like this:

  function loadAceEditor() {
    return import(/* webpackChunkName: "ace" */ 'ace-builds/src-noconflict/ace').then(() => {
      return import(/* webpackChunkName: "ace" */ 'ace-builds/webpack-r...

Cronjobs: "Craken" is dead, long live "Whenever"

Our old solution for cronjobs, the "craken" plugin, is no longer maintained and does not work on Rails 3.2+.

We will instead use the whenever gem.

"Whenever" works just like "craken", by putting your rake tasks into the server's cron table. Everything seems to work just like we need it.

Installation for new projects

  1. Add "whenever" to your Gemfile:

     group :deploy do
       gem 'whenever', require: false
     end
    
  2. Add it to your config/deploy.rb:
    ...

Auto-coerced virtual attributes with Virtus

We've since created ActiveType which has a restricted subset of Virtus' features. It might be enough for your needs.

We sometimes give our ActiveRecord models virtual attributes for values that don't need to be stored permanently.

When such a virtual attribute should contain integer values you might get unexpected behavior with forms, because every param is a string and you don't get the magic type casting that Rails would give you if it ...

MySQL 5.7.5 enables `ONLY_FULL_GROUP_BY` mode per default

When using GROUP BY, MySQL now complains if the SELECT includes columns which are not part of the GROUP BY.

Reason:

There could be multiple values for those columns per group but only one value can be picked for the results.

The default behaviour of MySQL prior to version 5.7 will not complain and arbitrarily choose a value. But this leads to non-deterministic results. So MySQL now has enabled the only_full_group_by setting by default to prevent this.

In Rails this could lead to some trouble, because scopes do not have sp...

How to make programming hard for yourself

For all of my professed admiration of Ruby on rails, I personally don't think that easier and more productive CRUD application writing will shake things up. I personally care very much about writing applications in a tenth of the time, but using Rails is like listening to Jaco Pastorius. The real learning experience comes when you try to duplicate the feat.

Things to consider when using Travis CI

Travis CI is a free continuous integration testing service. However, it is really fragile and will break more than it will work.

If you choose to use it anyway, learn the lessons we already learnt:

Use a compatible Rubygems for Rails 2.3 on Ruby 1.8.7

Ruby 1.8.7 is not compatible with current Rubygems versions (> 2.0). Runnig rvm rubygems latest-1.8 --force will fix this and install Rubygems version 1.8.29.

To make Travis CI do this, add `before_script: rvm rubygems latest-1....

Delete a Clearance session after some time of inactivity

This note describes how to kick a user out of a Rails application after she hasn't requested an action for a while. Note that this is different from deleting sessions some time after the last login, which is the default.

Also note that this is probably a bad idea. Most sites keep sessions alive forever because having to sign in again and again is quite inconvenient for users and makes your conversion rates go down the toilet. [The Clearance default is to keep sessions around for one year](https://makandracards.com/makandra/701-when-sessio...

A few hints when upgrading to Ruby 1.9

Note: If you are currently working with Ruby 1.8.7 or 1.9.3, we recommend to upgrade to Ruby 2.1 first. From our experience this upgrade is much smoother than the jump from 2.1 and 2.2, while still giving your the huge performance gains of Ruby 2. Also, if you're on Ruby 1.8.7, we recommend to skip a troublesome upgrade to 1.9.3 and go straight to 2.1.


When trying to make a Rails app run on Ruby 1.9, you're likely to encounter several issues. Here are a few solutions (obviously not exhaustive):

When running `bundle ...

Deal with certain travis CI failures

Travis changed their default distribution from Ubuntu 14.04 (trusty) to 16.04 (precise). This might break your test setup for new builds.

You can solve this issue by freezing your test distribution in the .travis.yml to Ubuntu 14.04 until you have the time to solve all the issues you will have in 16.04:


dist: trusty

Error details

Here are few indicators that you ran into this issue:

Connection to the PostgreSQL database does not work anymore

Your travis-ci builds might have started failing on the usual

psql -c...

Yarn: How to recognize that you are using a different node version than your colleagues

The issue in this card can occur if the node_modules directory is checked into your Git repository. We usually recommend to exclude node_modules from version control.

In any case you should document which version of node to use in your project in a .nvmrc file.


I saw a strange behaviour after we introduced webpack in one of our projects and finally found out the reason: The person who committed the files used a node version that is older than mine.

Every time I wanted to run my rai...

Resque: Clearance authentication for dashboard

Resque comes with its own dashboard (Resque server) that you can mount inside your Rails 3 application with

#config/routes.rb:

require 'resque/server'

My::Application.routes.draw do
  # ...

  mount Resque::Server => '/resque'
end

Unfortunately, since this bypasses the filters in your ApplicationController, everyone can access this dashboard now (unless you have some Rack-based authentication in place, like Devise).

If you're using ...

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

jpmcgrath/shortener

Shortener is a Rails Engine Gem that makes it easy to create and interpret shortened URLs on your own domain from within your Rails application. Once installed Shortener will generate, store URLS and “unshorten” shortened URLs for your applications visitors, all whilst collecting basic usage metrics.

rails/activeform

A different take on what we're doing with ActiveType. Since it lives under the rails organization it might be part of Rails 5?

EdgeRider 0.3.0 released

EdgeRider 0.3.0 adds support for Rails 4.1 and Ruby 2.1. It forward-ports ActiveRecord::Base.scoped to Rails 4.1.

Using Arel to Compose SQL Queries

Arel is a library that was introduced in Rails 3 for use in constructing SQL queries. Every time you pass a hash to where, it goes through Arel eventually. Rails exposes this with a public API that we can hook into when we need to build a more complex query.