Using Ruby's Method objects for inspecting methods

Do you remember finding where a method is defined?

I recently that Method objects are quite useful within a debugging feast to find out the currently defined internals of methods, because they are either called within the current context or because you want to learn something about the API of the current objects.

Why is this useful?

This is especially useful since Ruby is an interpreted language an...

Use rbenv-each to run a command for every installed Ruby version

The linked rbenv plugin rbenv-each is very helpful to keep QoL gems up to date that are not part of the Gemfile.

For example, you can bump the geordi version for all your rubies with the following command:

rbenv each gem update geordi

Another useful example would be to bulk-update bundler or rubygems.

Note that rbenv-each hasn't been updated since 2018, but it is fully functiona...

Don't use log level :debug in your production environments

Catch phrase

You don't want sensitive user data in your logs.

Background

Rails per default filters sensitive data like passwords and tokens and writes [FILTERED] to the logs. The code which is responsible for enabling that usually lives in filter_parameter_logging.rb (Rails.application.config.filter_parameters). Here is an example of a filtered log entry:

Unfiltered:
`User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."token" = $1 LIMIT $2 [["token", "secret-token"], ["LIMIT", 1]]`

After the filter is appl...

Advanced plotting in Ruby with Gnuplot

Besides Plotting graphs in Ruby with Gruff, which comes handy for many uses cases, you sometimes might need configuration for more advanced plots, e.g. for academic concerns. Then using Gnuplot, the first academic open source plotting software, might be a good option.

There are several wrappers for Ruby available and I mainly looked at one of the two most frequently used ones, which are [ruby_gnuplot](https://github.com/rdp/ruby_gnuplot...

Split your parallel tests by execution time and keep execution logs up to date

Both knapsack and parallel_tests have the option to split groups by historic execution time. The required logs for this might be outdated since you manually have to update and push them into your repository.

The following card includes an option how you can keep them consistently up to date with no extra effort locally and/or remotely.

How to always split by execution logs

Parallel Tests

The parallel_tests gem has the option flag `--group...

Lightning Talk: Coverage based Test Case Prioritization in Ruby on Rails

For my computer science bachelor's thesis I programmed and evaluated a CLI Test Case Prioritization (TCP) tool for makandra. It has been written as a Ruby Gem and was tested and evaluated against one Ruby on Rails project. This card will summarize and present the research results, the evaluation and the programmed CLI tool.

The code has been published for educational purposes on GitHub. The german bachelor's thesis has also been included for download at the end.


...

Do not pass params directly into url_for or URL helpers

Rails' url_for is useful for generating routes from a Hash, but can lead to an open redirect vulnerability.

Your application's generated route methods with a _url suffix are also affected because [they use url_for unter the hood](https://github.com/rails/rails...

CarrierWave: Processing images with libvips

When you write your next CarrierWave uploader, consider processing your images with libvips instead of ImageMagick.

Reasons for libvips

There are several upsides to using libvips over ImageMagick:

RubyMine: Fixing "Rubocop returned exit code -1. See the logs for details"

When RubyMine reports Rubocop returning "exit code -1", upgrading Rubocop can be the fix:

gem install rubocop

"The logs" can be accessed with Ctrl + Shift + A > Show log in (Files). This opens your file manager at the IDEA log location; the log file is called "idea.log".
If your operating system supports it, right click into the file manager > Open in Terminal. There run tail -f idea.log to follow the log.

Ruby: alias_method conflicting with prepend

alias_method makes a copy of a method. This works fine until the same method is overridden using prepend. If the prepend is executed after alias_method, you'll either see an infinite loop, or loose the prepended functionality.

Solution

Your options are:

  • Ensure prepend happens before alias_method
  • If you can control the alias_method invocation: rewrite to the modern & better prepend
  • If you can only control the prepend invocation: rewrite to the legacy alias_method

Best practice: How to manage versions in a Gemfile

It most cases it's not necessary to add a version constraint next to your gems in the Gemfile. Since all versions are saved in the Gemfile.lock, everyone running bundle install will get exactly the same versions.

There are some exceptions, where you can consider adding a version constrain to the Gemfile:

  • You are not checking in the Gemfile.lock into the version control (not recommended)
  • A specific gem has a bug in a more recent version (adding a comment for the reason is highly recommended)
  • You want to ensure no one upgrade...

How to pretty print all values in a Redis database

With this Ruby script you can print all values in a Redis database to your console (derived from this bash script).

Note: Do not run this command in production. This is for debugging purposes only.

def pretty_print_redis(redis)
  redis.keys.each_with_object({}) do |key, hash|
    type = redis.type(key)

    hash[key] = case type
    when 'string'
      redis.get(key)
    when 'hash'
      redis.hgetall(key)
    when 'list'
      redis.lrange(key, 0, -1)
    when 'set'
      redis.smembers(...

ASDF: A Version Manager To Rule Them All

tl;dr

asdf allows you to manage multiple runtime versions with a single CLI tool and is backwards compatible by supporting existing config files, like e.g. .nvmrc or .ruby-version.

Getting Started

  1. Disable rbenv
    1.1 Delete or comment out source /home/$user/.rbenvrc in ~/.profile
    1.2 Delete or comment our eval "$(rbenv init -)" in ~/.bashrc or ~/.zshrc
    1.3 To take effect you may have to restart your shell or log out and log in again from your current linux session
  2. Install asdf by following the official ...

ActiveRecord::Relation#merge overwrites existing conditions on the same column

In Ruby on Rails ActiveRecord::Relation#merge overwrites existing conditions on the same column. This may cause the relation to select more records than expected:

authorized_users = User.where(id: [1, 2])
filtered_users   = User.where(id: [2, 3])
authorized_users.merge(filtered_users).to_sql
# => SELECT * FROM users WHERE id IN (2, 3)

The merged relation select the users (2, 3), although we are only allowed to see (1, 2). The merged result should be (2).

This card explores various workarounds to combine two scopes so t...

How to create a multiline map in SASS/SCSS

If you want to to create maps within SASS/SCSS-files, it normally works like this:

$some-map: (key1: value1, key2: value2)

However, some maps can get big really fast, if they are being used to contain all of the project's icon names and their sizes for example.
Therefore splitting a map into multiple lines, like we do it in Ruby with big hashes, would become really handy.

Unfortunately SASS doesn't support multiline maps. There has been an open issue since 2011 and it hasn't been...

How Haml 6 changes attribute rendering, and what to do about it

Haml 6 was a major rewrite with performance in mind. To achieve a performance improvement of 1.7x, some design trade-offs had to be made. The most notable change might be the simplified attribute rendering.

In Haml 5, attribute rendering knew two special cases: an attribute with value true would be rendered without a value, an attribute with a falsy value would not be rendered at all. All other values would just be rendered as attribute values.

According to the Haml maintai...

Using Capybara finder methods with arbitrary matching conditions

Capybara has a variety of finder methods like find_button to help you look up DOM elements. There are also matchers like have_field to make expectations during tests.

These methods also have a number of options to influence the lookup. E.g. the :disabled option lets you control whether Capybara will match disabled fields.

If you have a matching condition that cannot be expressed by the existing Capybara opt...

Rails: Your index actions probably want strict_loading

By activating strict_loading you force developers to address n+1 queries by preloading all associations used in the index view. Using an association that is not preloaded will raise an ActiveRecord::StrictLoadingViolationError.

I think it's a good default to activate strict_loading in your controllers' #index actions. This way, when a change introduces an n+1 query, you...

How to exclusively lock file access in ruby

We will achieve this by creating a block accepting method to optionally create and then lock a .lock File of the underlying accessed file.

Why create a .lock file?

  • The main advantage of creating a .lock file is that #flock might block some operations and require the index node of the file to be consistent. Some operations might change that index node.
  • In some cases it might also be convenient to just read/write the lock file first and update the other file afterwards or vice versa, such that breaking of a process does not...

How to enable template coverage support for simplecov

Since Ruby 3.2.0 you can measure coverage support for eval statements and support has been added for the simplecov gem as well.

This allows to track coverage across ruby templates such as haml, erb, ...

Simply set this within simplecov

SimpleCov.start do
  enable_coverage_for_eval
end

Heads up: Deployment with newly generated SSH key (using ED25519) might fail

If you use a newer SSH key generated with the ED25519 algorithm instead of RSA (see Create a new SSH key pair), the deployment with Capistrano may fail with the following message:

The deploy has failed with an error: unsupported key type `ssh-ed25519'
net-ssh requires the following gems for ed25519 support:
 * ed25519 (>= 1.2, < 2.0)
 * bcrypt_pbkdf (>= 1.0, < 2.0)
See https://github.com/net-ssh/net-ssh/issues/565 for more information
Gem::LoadError : "ed25519 i...

Issue Checklist Template

This is a checklist I use to work on issues. For this purpose I extracted several cards related to the makandra process and ported them into a check list and refined that over time a little bit.

This task list is divided by the Gate keeping process in the following steps:

1. Starting a new feature
2. Working on the issue
3. Finishing a feature
4. After Review

Here are some ti...

Rails: Using database default values for boolean attributes

In the past we validate and set default values for boolean attributes in Rails and not the database itself.

Reasons for this:

  • Older Rails didn't support database defaults when creating new records
  • Application logic is "hidden" in the database

An alternative approach, which currently reflects more the general opinion of the Rails upstream on constraints in the database, is adding default values in the schema of the database itself. We also ...

HTTP headers can only transport US-ASCII characters safely

HTTP header values must only contain low-ASCII (7-bit) characters for safe transport. From RFC 7230:

Historically, HTTP has allowed field content with text in the ISO-8859-1 charset [ISO-8859-1], supporting other charsets only through use of [RFC2047] encoding. In practice, most HTTP header field values use only a subset of the US-ASCII charset [USASCII]. Newly defined header fields SHOULD limit their field values to US-ASCII octets.

If you need to transport 8-bit+ characters (e.g...