Linked content

Tailwind versus BEM

The linked article compares two approaches for writing CSS:

  • A component library (like BEM)
  • Utility classes (like Tailwind)

It's good to know the pros and cons of each approach. Although we default to BEM, you might encounter a utility approach in a clinet project.

Ruby: Comparing a string or regex with another string

In Rubocop you might notice the cop Style/CaseEquality for e.g. this example:

def foo(expected, actual)
  expected === actual

In case expected is a Regex, it suggests to change it to the following pattern:

def foo(expected, actual)

In case expected is a Regex or a String, you need to keep ===. Otherwise the actual expression is always converted to a regular expression.

# For expected === actual
foo('Test(s)', 'Test(s)') #=> true

# For expected.match?(actual)

Ruby: A short summary of available hooks in Cucumber

Here is a short summary of Cucumber hooks in Ruby taken from Note that the BeforeStep is currently not existing in the Ruby implementation of Cucumber.

Before hooks run before the first step of each scenario.

Before do |scenario|

After hooks run after the last step of each scenario, even when the step result is failed, undefined, pending or skipped.



When you want to format only line breaks, you probably do not want simple_format

For outputting a given String in HTML, you mostly want to replace line breaks with <br> or <p> tags.
You can use simple_format, but it has side effects like keeping some HTML.

If you only care about line breaks, you might be better off using a small, specialized helper method:

def format_linebreaks(text)
  safe_text = h(text)
  paragraphs = split_paragraphs(safe_text).map(&:html_safe)

  html = ''.html_safe
  paragraphs.each do |paragraph|
    html << content_tag(:p, paragraph)



Reading an element's attributes with Capybara

capybara_element['attribute_name'] allows accessing an element's attributes in Capybara.

A few examples:

# => "first-class second-class"

# => "My placeholder value"

# => ""

# => nil

How to negate scope conditions in Rails

Rails does not offer a "vanilla" way of negating an ActiveRecord scope. Here are two ways to do it yourself without too much effort.


class User
  scope :admins, -> { where(role: ['admin', 'superuser'] }
  # ...

Now what if we want a scope of users that are not admins? While you could declare a second scope like scope :non_admins, -> { where(role: ['guest', 'editor']) }, there are ways to use the opposite of the admins scope.

Option A: Subquery

You could just use a subquery. Doing that with scopes is easy...


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

Migrate gem tests from Travis CI to Github Actions with gemika

We currently test most of our gems on Travis CI, but want to migrate those tests to Github Actions. This is a step-by-step guide on how to do this.

Note that this guide requires the gem to use gemika.

  1. Go to a new "ci" branch:
    git checkout -b ci
  2. Update gemika to version >= 0.5.0.
  3. Have gemika generate a Github Actions workflow definition by running
    mkdir -p .github/workflows; bundle exec rake gemika:generate_github_actions_workflow > .github/workflows/test.yml


How to downgrade Google Chrome in Ubuntu

If you're experiencing problems with your Google Chrome installation after an update, it might help downgrading Chrome to check if the problem disappears. Keep in mind though that running outdated software, especially web browsers, is in most cases not a good idea. Please verify periodically if you still need to run the old version or if an even more recently updated version fixes the problems introduced in your version.

Here's how to get old versions of Chrome for your Ubuntu installation:

First, go to [UbuntuUpdates](https://www.ubuntuup...


Debugging SPF records

While debugging a SPF record I found to be very helpful.

  • it lists all IPs that are covered by the SPF record
  • shows syntax errors
  • helps you debugging errors like DNS lookup limit reached
  • it also lets you test a new SPF strings before applying it. This can save you time as you don't have to loop with operations

Also the advanced check at has a very good interface to test new SPF policies.

Installing Ruby <= 2.3 on Ubuntu 20.04+

Installing old Rubies (<= 2.3) with a standard rbenv + ruby-build is no longer possible on Ubuntu 20.04. This is because those Rubies depend on OpenSSL 1.0 which is no longer shipped with current Ubuntus.

We have forked ruby-build with a workaround that makes it compile and statically link the latest OpenSSL 1.0 version. This works on Ubuntu 20.04, as well as on Ubuntu 18.04.

To switch to our fork of ruby-build, update ruby-build like this

git -C ~/.rbenv/plugins/ruby-build remote add makandra...
Auto-destruct in 32 days

Geordi 4.2.0 released

We released a new version of our gem geordi

4.2.0 2020-10-02

Compatible changes

  • Add auto_update_chromedriver as global setting option to automatically update chromedriver before cucumber
    tests, if Chrome and chromedriver versions don't match.
  • Dump command: Add support for multiple databases
  • Add Ruby 2.7 to list of supported Ruby versions
  • Fix #115: geordi cucumber --modified command, that corrupted filenames like:
    No such file or directory tures/pages.feature
  • Avoi...

Cucumber step to match table rows with Capybara

These steps are now part of Spreewald.

This note describes a Cucumber step that lets you write this:

Then I should see a table with the following rows:
  | Bruce Wayne       | Employee    | 1972 |
  | Harleen Quinzel   | HR          | 1982 |
  | Alfred Pennyworth | Engineering | 1943 |

If there are additional columns or rows in the table that are not explicitely expected, the step won't complain. It does however expect the rows to be ordered as stat...

Security issues with hash conditions in Rails 2 and Rails 3

Find conditions for scopes can be given either as an array (:conditions => ['state = ?', 'draft']) or a hash (:conditions => { 'state' => 'draft' }). The later is nicer to read, but has horrible security implications in some versions of Ruby on Rails.

Affected versions

Version Affected? Remedy
2.3.18 yes Use chain_safely workaround
3.0.20 no ...

How to implement simple queue limiting/throttling for Sidekiq

The sidekiq-rate-limiter gem allows rate-limiting Sidekiq jobs and works like a charm. However, it needs to be integrated on a per-worker basis.

If you want to limit a whole queue instead, and if your requirements are simple enough, you can do it via a Sidekiq middleware yourself.

Here is an example that limits concurrency of the "mailers" queue to 1. It uses a database mutex via the [with_advisory_lock](

Rails: How to list all validations on a model or an attribute

If a model inherits from others or uses many concerns / traits, it might be hard to see in the code which validators it has.
But fortunately there's a method for that:

irb(main):002:0> pp UserGroup.validators
  @delimiter=[true, false],
  @options={:in=>[true, false], :allow_nil=>false}>,
  @delimiter=[true, false],
  @options={:in=>[true, false], ...
Auto-destruct in 23 days

Cucumber Factory 2.2.0 released

Version 2.2.0 of our gem Cucumber Factory has been released.

  • A step was added that allows modifying existing records with a similar syntax to creating new records:
    (Given "Bob" is a user)
      And "Bob" has the email "" and is subscribed
    • This step will also work with doc strings or tables:
    (Given "Bob" is a user)
      And the user above has these attributes:
      | name  | Bob         |
      | email | | 
This website uses short-lived cookies to improve usability.
Accept or learn more