During deployment: "You are trying to install in deployment mode after changing your Gemfile"

While deploying an Ruby update to an old application these days, we encountered the following misleading error:

*** [err :: some-host.makandra.de] You are trying to install in deployment mode after changing
*** [err :: some-host.makandra.de] your Gemfile. Run `bundle install` elsewhere and add the
*** [err :: some-host.makandra.de] updated Gemfile.lock to version control.
*** [err :: some-host.makandra.de] 
*** [err :: some-host.makandra.de] You have deleted from the Gemfile:
*** [err :: some-host.makandra.de] *

We found out a newe...

Why you can't use timezone codes like "PST" or "BST" for Time objects

Rails' ActiveSupport::TimeWithZone objects have both a timezone code and offset, e.g. Thu, 28 Mar 2019 16:00:00 CET +01:00. Ruby's stdlib TZInfo also has time zones, but with different identifiers.
Unfortunately, not all timezone codes can be used to parse strings or to move time objects into another time zone.

Some timezone codes like CET are supported by ActiveSupport extensions like String#in_time_zone, while many codes will actually not work:

>> '2019-03-01 12:00'.in_time_zone('PST')
ArgumentError (Invalid Timezone: PST)
...

How to install bundler for Ruby < 2.3

Bundler 2 requires at least Ruby 2.3.0 and RubyGems 2.5.0. You might get the following error when you try to install bundler for Ruby < 2.3:

ERROR:  Error installing bundler:
	bundler requires Ruby version >= 2.3.0.

To fix this error upgrade your project's ruby version or install the last supported version of Bundler for Ruby < 2.3:

gem install bundler -v '~>1'

You will also see an error if your [RubyGems versi...

Rails asset pipeline: Using ESNext without a transpiler

If your app does not need to support IE11, you can use most ES6 features without a build step. Just deliver your plain JavaScript without transpilation through Babel or TypeScript, and modern browsers will run them natively.

Features supported by all modern browsers include:

  • fat arrow functions (() => { expr })
  • let / const
  • class
  • async / await
  • Promises
  • Generators
  • Symbols
  • Rest arguments (...args)
  • Destructuring

You won't be able to use import and export, or use npm modules.

See this [ES6 compatibility mat...

Upgrading Ruby from 1.8.7 to 2.3.5

Suggested Workflow

Set the ruby version in .ruby-version to 2.3.5, then perform these steps one by one, fixing errors as they occur:

  1. Update gems as listed below, and bundle
  2. Boot a Rails console - see below for a list of changes you will probably need
  3. Run Specs with --backtrace option
  4. Run Cucumber features (with Geordi's --debug option)
  5. When all tests are green, look through your Gemfile and remove as many version constraints as possible.
  6. Boot the application in different environements to spot further issues, e...

How to create a Basic Auth header value

When doing Basic Authentication, your browser will send an "Authorization" header. Its value is simply a Base64-encoded representation of "username:password" (like when you place credentials in the URL directly). Example for "user@example.com" with password "secret":

Authorization: Basic dXNlckBleGFtcGxlLmNvbTpzZWNyZXQ=

So, in Ruby, you can create such headers like so:

Base64.strict_encode64("#{username}:#{password}")

Note that when speaking to a REST API, you should be using libraries like RestClient or HTTParty which will wrap ...

Ruby: Reading and writing CSVs

In ruby you can easily read and write CSVs with the standard CSV library class.

On top of this, you can use the gem smarter_csv for reading (not writing) CSVs in a more comfortable way:

  • Keep in mind, that the development of this gem is in an unknown state and the 2.0 release seems to happen never
  • The API will change completely for 2.0, so you might find a bunch of unrelated documentation for 1.2

Here is an example...

How to upgrade Rails: Workflow advice

When upgrading Rails versions -- especially major versions -- you will run into a lot of unique issues, depending on the exact version, and depending on your app.

However, it is still possible to give some generic advice on how you want to tackle the update in principle.

If you are not really confident about upgrading Rails, have a look at Rails LTS.

How many update steps?

Besides the Rails upgrade itself, you might also want to upgrade your other gems and upgrade your Ruby version.
First decide in how many st...

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

Regular tasks for long-running projects

When projects run for many years, they require special regular maintenance to stay fresh. This kind of maintenance is usually not necessary for small or quick projects, but required to keep long-running projects from getting stale.

You should be able to fit this into a regular development block.

Quarterly

Check which libraries need updating

As time goes by, libraries outdate. Check your software components and decide if any of it needs an update. Your main components (e.g. Ruby, Rails, Unpoly) should always be reasonably up to d...

Rubymine FileType mismatch

If your Rubymine does not recognize a file type correctly although you have entered the unmistakeable file extension like material_orders_controller.rb, this may help you:

Causing the Problem

Sometimes you create a new file and forget to enter the ending like material_orders_controller
Rubymine handles such files per default as simple txt files.
You delete this file and create a new one with correct ending: material_orders_controller.rb. But still Rubymine treats this file as text file, no highlighting is available.

What happene...

How to access before/after pseudo element styles with JavaScript

Accessing pseudo elements via JavaScript or jQuery is often painful/impossible. However, accessing their styles is fairly simple.

Using getComputedStyle

First, find the element in question.

let element = document.querySelector('.my-element') // or $('.my-element').get(0) when using jQuery

Next, use JavaScript's getComputedStyle. It takes an optional 2nd argument to filter for pseudo elements.

let style = window.getComputedStyle(element, '::before')
let color = style.getPropertyValue('background-color...

RubyMine: How to add a german spell checker

Since the Spell checker german dictionary plugin is not maintained anymore, here is another way to use a german dictionary.

  1. Install the Hunspell plugin and restart Ruby Mine
  2. Run sudo apt install hunspell-de-de
  3. Select /usr/share/hunspell/de_DE.dic in File > Settings > Editor > Spelling > Custom Directory +

![Screenshot_from_2018-10-17_16-47-03.png](https://makandracards.com/makandra/57341-rubymine-how-to-add-german-spell-checker...

Ruby: required keyword arguments in the pre-2.1 era

Starting with Ruby 2.0 you can define methods with keyword arguments.

In 2.1+ required keyword arguments can be defined by using a colon without default value:

def match(value, ignore:)
  # ...
end

To accomplish something similar in ruby 1.8, use:

def match(value, options = {})
  ignore = options.fetch(:ignore)
  # ...
end

How to examine an unknown Ruby object

When debugging your application, you will come across objects created by some gem or framework. You don't have the source code at hand, still need to inspect this object. Here are some tools to do so:

Relevant methods

@object.methods - Object.instance_methods returns a list of methods excluding methods inherited from Object. This makes the methods list drastically more relevant. You can also try subtracting other base classes like ActiveRecord::Base.methods etc.
To further narrow it down you can also just look at public methods...

Rbenv: How to remove a gem installed from a Github source

Normally you can list all gems of the current ruby version with gem list, which also includes the gems of you Gemfile. These can be uninstalled with gem uninstall gemname.

List and uninstall a gem installed via Bundler from Github

This does not work for gems installed directly from Github. They do not appear in gem list.

Show all gems installed via Github by bundler:

ls ~/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/bundler/

Remove a gem installed via Github by Bundler:

rm -rf ~/.rbenv/versions/2.4.1/lib/ruby/gems/2....

An incomplete guide to migrate a Rails application from paperclip to carrierwave

In this example we assume that not only the storage gem changes but also the file structure on disc.

A general approach

Part A: Create a commit which includes a script that allows you to copy the existing file to the new file structure.

Part B: Create a commit which removes all paperclip logic and replace it with the same code you used in the first commit

Part A

Here are some implementation details you might want to reuse:

  • Use the existing models to read the files from
  • Use your own carrierwave models to write t...

Raising JavaScript errors in Ruby E2E tests (RSpec, Cucumber)

A JavaScript error in an E2E test with Selenium will not cause your test to fail. This may cause you to miss errors in your frontend code.

Using the BrowserConsole helper below you can check your browser's error console from your E2E tests.

The following will raise BrowserConsole::ErrorsPresent if there is an error on the browser console:

BrowserConsole.assert_no_errors!

Ignoring errors

You can ignore errors by their exact message:

BrowserConsole.ignore('Browser is burning')

You can ignore errors with me...

Ruby: How to use prepend for cleaner monkey patches

Let's say you have a gem which has the following module:

module SuperClient

  def self.foo
    'Foo'
  end
  
  def bar
    'Bar'
  end

end

For reasons you need to override foo and bar.

Keep in mind: Your code quality is getting worse with with each prepend (other developers are not happy to find many library extensions). Try to avoid it if possible.

  1. Add a lib/ext/super_client.rb to your project (see How to organize monkey patches in Ruby on Rails projects)
  2. Add the extension, which ov...

How to make changes to a Ruby gem (as a Rails developer)

At makandra, we've built a few gems over the years. Some of these are quite popular: spreewald (> 1M downloads), active_type (> 1M downloads), and geordi (> 200k downloads)

Developing a Ruby gem is different from developing Rails applications, with the biggest difference: there is no Rails. This means:

  • no defined structure (neither for code nor directories)
  • no autoloading of classes, i.e. you need to require all files yourself
  • no active_support niceties

Also, their scope...

Haml: Generating a unique selector for an element

Having a unique selector for an element is useful to later select it from JavaScript or to update a fragment with an Unpoly.

Haml lets you use square brackets ([]) to generate a unique class name and ID from a given Ruby object. Haml will infer a class attribute from the given object's Ruby class. It will also infer an id attribute from the given object's Ruby class and #id method.

This is especially useful with ActiveRecord instances, which have a persisted #id and will hence **generate the same selector o...