Installing Ruby 2.3 or below on Ubuntu 17 and above

From Ubuntu 17, rbenv fails to install Ruby below 2.4 because of a mismatching OpenSSL dependency: it needs libssl1.0-dev for the installation process, but recent Ubuntus come with libssl-dev.

From the linked StackOverflow comment:

As far as I know (and tested), Ruby versions < 2.4 requires libssl1.0, while >2.4 libssl1.1+. The two libssl packages conflict with each other, so you can't have both of them, so I had to juggle the libs in order to install the required ruby version. To make things even funnier (or more complicated),...

Git: Apply a diff

git apply allows you to apply a diff onto your HEAD. Most often you can achieve the same result with a rebase & merge.

Example:

master                commit1 - commit3
feature-branch                \ commit2 - commit4
git checkout feature-branch
git reset --hard commit3
git diff ..commit4 | git apply
master                commit1 - commit3
feature-branch                          \ Unstaged commit 2 & 4

You can also [create a patch and apply it afterwards](https://makandracards.com/makandra/2521-git-how-to...

RubyMine: Efficiently filtering results in the "Finder" overlay

RubyMine comes with a nice way to grep through your project's files: The finder (ctrl + shift + f). Don't be discouraged about the notice 100+ matches in n+ files if your searched keyword is too general or widely used in your project.

Image

RubyMine comes with a few ways to narrow down the resulting list, don't hesitate to apply those filters to speed up your search. Your keybinding might vary based on your personal settings.

File mask (alt + k)

If you already know the file extension of your ...

Capybara: Quick checking for element presence (without retries or timeout)

Element finding is a central feature of Capybara. Since #find is normally used to get elements from the current page and interact with them, it's a good thing that some Capybara drivers (e.g. Selenium) will wait an amount of time until the expected element shows up. But if Capybara cannot #find it at all, you'll get an error.

if page.find('.that-element')
  # Do something
else
  # Never happens because #find raises
end

In order to simply check whether an element is present, without errors raised, you can use #has_css?. It...

Jasmine: using async/await to write nice asynchronous specs

Jasmine has long standing support for writing asynchronous specs. In days gone by we used the done callback to achieve this, but these days it is possible to write much more readable specs.

Async specs

As a first example, say we want to check that some form disables the submit button while working.

// bad (how we used to do it)

beforeEach(() => {
  this.form = setupMyForm()
  this.submitButton = findTheSubmitButton()
})

it('disables the submit button while working', (done) => {
  expect(this.submitButton.disabled).toBe(false)
...

Adding Jasmine JavaScript specs to a Webpack(er) project

The goal is to get Jasmine specs running in a Rails project using Webpacker, with the browser based test runner. Should be easily adaptable to a pure Webpack setup.

Image

Step 1: Install Jasmine

yarn add jasmine-core

Step 2: Add two separate packs

Since we do not want to mix Jasmine into our regular Javascript, we will create two additional packs. The first only contains Jasmine and the test runner. The second will contain our normal application code and the specs themselves.

We cannot...

How to get a backtrace if rspec (or any other ruby process) hangs with no output

If rspec hangs with no output and you dont get a backtrace neither with --backtrace nor by just killing it with crtl-c,
you can put the following in your spec/spec_helper.rb:

puts "rspec pid: #{Process.pid}"

trap 'USR1' do
  threads = Thread.list

  puts
  puts "=" * 80
  puts "Received USR1 signal; printing all #{threads.count} thread backtraces."

  threads.each do |thr|
    description = thr == Thread.main ? "Main thread" : thr.inspect
    puts
    puts "#{description} backtrace: "
    puts thr.backtrace.join("\n")
  end

...

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

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

Documenting your project's Node.js version in .nvmrc

Not all versions of Node.js are compatible with each other. Also npm packages may require a minimum or maximum version of Node.js. We use nvm on our development PCs so we can operate multiple versions of Node.js in parallel.

To make sure that all developers use a compatible version of Node.js, your project should declare the required Node.js in a file called .nvmrc.

When a .nvmrc exists, developers can cd in your project directory and activate the p...

Selenium may break with ChromeDriver 75+

When you update your ChromeDriver to version 75 or beyond, you might get w3c errors in your tests.

For example, reading the browser console for errors no longer works, and page.driver.browser.manage.logs.get(:browser) will raise an error like "undefined method `log' for #<Selenium::WebDriver::Remote::W3C::Bridge:0x000055903f307aa8>".

Add options.add_option('w3c', false) to your Selenium configuration (e.g. features/support/selenium.rb) and you should be back to normal:

Capybara.register_driver :selenium do |app|
  options ...

cucumber_factory: How to keep using Cucumber 2 Transforms in Cucumber 3

Cucumber up to version 2 had a neat feature called Step Argument Transforms which was dropped in favor of Cucumber 3 ParameterTypes. While I strongly encourage you to drop your legacy Transforms when upgrading to Cucumber 3, it might not always be possible due to their different design.
This is a guide on how to keep the exact same functionality of your old Transforms while writing them in the style of new `Paramet...

no passenger served applications running error when deploying via capistrano

When deploying with capistrano it's possible you get this "error" message:

*** [err :: example.com] There are no Phusion Passenger-served applications running whose paths begin with '/var/www/example.com'.
*** [err :: example.com] 

This is just because there were no running passenger process for this application on the server which could be restarted. It's not a real error. The application process will start if the first request for this app hits the appserver.

The output appears as err because it's printed to stderr.

Dep...

Heads up: Capybara 3's text matchers no longer squish whitespace by default

Until Capybara 2, node finders that accept a text option were able to find nodes based on rendered text, even if it spans over multiple elements in the HTML. Imagine a page that includes this HTML:

<div class='haystack'>
  Hi!
  <br>
  Try to match me.
</div>

Even though the text is separated by a <br> tag in the HTML, it is matched until Capybara 2 which used to "squish" text prior to the comparison.

# Capyabara 1 or 2
page.find(...

Events triggered by jQuery cannot be observed by native event listeners

jQuery has a function $.fn.trigger(). You can use it to dispatch an event on a jQuery object:

let $element = $('.foo')
$element.trigger('change')

A caveat is that such an event will be received by jQuery event listeners, but not by native event listeners:

let $element = $('.foo')

$element.on('change', event => console.log('I will be called'))
$element[0].addEventListener('change', event => console.log("I WON'T be called"))

$element.trigger('change')

This is not an issue when your entire app is ...

Webpack: How to split your bundles

To keep JavaScript sources small, it can sometimes make sense to split your webpack bundles. For example, if your website uses some large JavaScript library – say TinyMCE – which is only required on some selected pages, it makes sense to only load that library when necessary.

In modern webpack this is easily doable by using the asynchronous import function.

Say we have an unpoly compiler that sets up TinyMCE like this (code is somewhat simplified):

// TinyMCE as part of the main bundle!

import tinymce from 'tinymce/tinymce'

// U...

Capybara: Testing file downloads

Download buttons can be difficult to test, especially with Selenium. Depending on browser, user settings and response headers, one of three things can happen:

  • The browser shows a "Save as..." dialog. Since it is a modal dialog, we can no longer communicate with the browser through Selenium.
  • The browser automatically downloads the file without prompting the user. For the test it looks like nothing has happened.
  • The browser shows a binary document in its own window, like a PDF. Capybara/Selenium freaks out because there is no HTML docum...

SameSite cookies

TL;DR Most web applications do not require action on this. SameSite=None (old browser default) will continue to work, and SameSite=Lax (new Chrome default, gradually rolled out) is an even better default for cookies. Set SameSite=Strict only for extra security in special cases (see below). If your application is rendered in an iframe (e.g. a video player or some news stream), you need to configure its relevant cookies as SameSite=None.


The SameSite cookie attribute targets **c...

Ruby: Using named groups in Regex

An alternative of using a multiple assignment for a Regex are named groups. Especially when your Regex becomes more complicates it is easier to understand and to process.

Note:

  • In case a string does not match the pattern, .match will return nil.
  • With Ruby 2.4 the result of .match can be transformed to a Hash with named_captures. This allows you to use methods like slice or fetch on the result.

Example with a mult...

Vortrag: Elasticsearch Grundlagen und Rails-Integration mit searchkick

Was ist Elastic?

  • Suchmaschine, basierend auf Apache Lucene
  • größtenteils Open-Source
  • einige kommerzielle Features ("Elastic Stack", früher "X-Pack")
    • Zugriffsrechte (bis vor kurzen)
    • Monitoring
    • Reporting
    • Graph-Unterstützung
    • Machine Learning
  • REST-Api (JSON über HTTP)

Grundlagen

Elastic antwortet per Default auf Port 9200

http GET :9200
{
  "name": "ntK2ZrY",
  "cluster_name": "elasticsearch",
  "cluster_uuid": "Bbc-ix5bQZij5vfFU29-Cw",
  "version": {
    "number": "6.7.1",
    "build_flavor": "...

How to test Autoprefixer and CSSnext in PostCSS

PostCSS is a tool for transforming styles with JS plugins. In Webpacker you can configure the plugins and their settings via the postcss.config.js file. Make sure that postcss-loader is part of your package.json.

module.exports = {
  plugins: [
    require('postcss-import'),
    require('postcss-flexbugs-fixes'),
    require('postcss-preset-env')({
      autoprefixer: {
        flexbox: 'no-2009'
      },
      stage: 3
    })
  ]
}

Note: Stage 3 means you can use all CSS features that ar...

How to avoid multiple versions of a package in yarn

To avoid multiple versions of a package, you can manually maintain a resolutions section in your package.json. We recommend you to do this for packages like jQuery. Otherwise the jQuery library attached to window might not include the functions of your packages that depend on jQuery.

Note: This is only an issue in case you want to use a package functionality from window e.g. $(...).datepicker() from your dev console or any other javascript within the application.

Background

By default yarn will create a folder node_modules ...

When reading model columns during class definition, you must handle a missing/empty database

When doing some meta-programming magic and you want to do something for all attributes of a class, you may need to access connection or some of its methods (e.g. columns) during class definition.

While everything will be fine while you are working on a project that is in active development, the application will fail to boot when the database is missing or has no tables. This means that Raketasks like db:create or db:migrate fail on a freshly cloned project.

The reason is your environment.rb which is loaded for Raketasks and calls...

Migration from the Asset Pipeline to Webpacker

This is a short overview of things that are required to upgrade a project from the Asset Pipeline to Webpacker. Expect this upgrade to take a few days even the diff is quite small afterwards.

Preparations

1. Find all libraries that are bundled with the asset pipeline. You can check the application.js and the application.css for require and import statements. The source of a library is most often a gem or a vendor directory.
2. Find an working example for each library in the application and write it down.
3. Find out the ver...