Ruby: A short summary of available hooks in Cucumber

Here is a short summary of Cucumber hooks in Ruby taken from https://github.com/cucumber/cucumber-ruby. 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|
  ...
end

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

...

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 in all your Gemfiles.
  3. Have gemika generate a Github Actions workflow definition by running
    mkdir -p .github/workflows; bundle exec rake gemika:generate_github_actions_workflow > .github/workf...
    

Installing old versions of mysql2 on Ubuntu 20.04+

On some of our older projects, we use the mysql2 gem. Unfortunately, versions 0.2.x (required for Rails 2.3) and versions 0.3.x (required for Rails 3.2) can no longer be installed on Ubuntu 20.04. Trying this either leads to errors when compiling the native extension, or a segfaults when using it.

For Rails 4.2, mysql2 version 0.4.10 seems to work okay. If you still have issues, upgrade to 0.5.x, which should be compatible.

To install it, you have to switch the mysql2 gem to our fork. In your Gemfile, ...

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

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](https://github.com/ClosureTree/wit...

VCR and the webdrivers gem

If you're using the webdrivers gem and VCR together, depending on your configuration, VCR will yell at you regulary.
The webdrivers gem tries to update your webdrivers on your local machine. To do so, it checks the internet for newer versions, firing an HTTP-request to e.g. https://chromedriver.storage.googleapis.com

You can "fix" this in multiple ways:

  1. Update your drivers on your machine with
    RAILS_ENV=test rake webdrivers:chromedriver:update

  2. Ignore the driver update-URL in your ...

Pagy

Pagy is a gem for pagination.
They make some bold claims:

Pagy is the ultimate pagination gem that outperforms the others in each and every benchmark and comparison.

Maybe this is worth trying out.

Ruby: How to determine the absolute path relative to a file

If you want to get the path of a file relative to another, you can use the expand_path method with either the constant __FILE__ or the method __dir__. Read this card for more information about __FILE__ and __dir__.

Example

Structure:

.
├── bin
│   ├── format_changelog
├── CHANGELOG.md

bin/format_changelog:

#!/usr/bin/env ruby

changelog_path = ? # How to get the path to ../CHANGELOG.md independent of the working dir of the caller
changelog = File.read(changelog_path)

# ... further actions...

Git: Search for text in all branches

To find a version containing the regular expression foo in the history of any branch:

git grep foo $(git rev-list --all)

You may also limit the search to a file extension, e.g. Ruby files (.rb) like this:

git grep foo $(git rev-list --all) -- *.rb

Ruby Jard: Just Another Ruby Debugger

Ruby Jard provides a rich Terminal UI that visualizes everything your need, navigates your program with pleasure, stops at matter places only, reduces manual and mental efforts.

Workflow: How to use a key management service to encrypt passwords in the database

This is an extract from the linked article. It shows an approach on how to implement encrypted passwords with the AWS Key Management Service (KMS).

For most applications it's enough to use a hashed password with a salt (e.g. the gem devise defaults to this).

Upon password creation

  1. Generate hash as hash of password + salt.

  2. Encrypt the hash with a public key from KMS (you can store the public key in your server code).

  3. In your database sto...

How to fix: Rails query logs always show lib/active_record/log_subscriber.rb as source

Rails 5.2+ supports "verbose query logs" where it shows the source of a query in the application log.
Normally, it looks like this:

  User Load (0.5ms)  SELECT "users".* FROM "users" WHERE ...
  ↳ app/controllers/users_controller.rb:42:in `load_users'

However, you may encounter ActiveRecord's LogSubscriber as the source for all/most queries which is not helpful at all:

  User Load (0.5ms)  SELECT "users".* FROM "users" WHERE ...
  ↳ activerecord (6.0.3.3) lib/active_record/log_subscriber.rb:100:in `debug'

While th...

Controlling issue grouping in Sentry

When you use Sentry to monitor exceptions, an important feature is Sentry's error grouping mechanism. It will aggregate similar error "events" into one issue, so you can track and monitor it more easily. Grouping is especially important when you try to silence certain errors.

It is worth understanding how Sentry's grouping mechanism works.

The default grouping mechanism

The exact algorithm has changed over time, and Sentry will keep using the algorithm t...

Clean your Rails routes: grouping

In Ruby on Rails, all the routes of a given application can be found within the config/routes.rb file.
You add more and more routes in this file as your project grows.

The problem here is that this file potentially becomes very complicated to manage over the time.
That’s why it’s important to find a way to order and maintain your routes.

See: Clean your Rails routes: grouping

Sometimes the routes.rb grows very fast and each line adds mo...

Ruby: Appending lines to a file in sync

When writing some logs to a file, that don't use Ruby's logger utility, it is often useful to sync them. So other process can read the output just in time.

Example with enabled sync

log_path = '/tmp/some_log.log'

log_file = File.open(log_path, 'a+')
log_file.sync = true

log_file.puts('Some log message')
File.read(log_path) #=> "Some log message\n"

log_file.puts('Some other message')
File.read(log_path) #=> "Some log message\nSome other message\n"

Example ...

Useful Ruby Pathname method

If you have a Ruby Pathname, you can use the method :/ to append filepaths to it.

With this method, Ruby code can look like this:

Rails.root/"features"/"fixtures"/"picture.jpg"

Alternatively you can use the #join method, which feels less magic:

Rails.root.join('features', 'fixtures', 'picture.jpg')

How to check if a file is a human readable text file

Ruby's File class has a handy method binary? which checks whether a file is a binary file. This method might be telling the truth most of the time. But sometimes it doesn't, and that's what causes pain. The method is defined as follows:

# Returns whether or not +file+ is a binary file.  Note that this is
# not guaranteed to be 100% accurate.  It performs a "best guess" based
# on a simple test of the first +File.blksize+ characters.
#
# Example:
#
#   File.binary?('somefile.exe') # => true
#   File.binary?('somefile.txt') # => fal...

PostgreSQL: How to use with_advisory_lock to prevent race conditions

If you want to prevent that two processes run some code at the same time you can use the gem with_advisory_lock.

What happens

  1. The thread will wait indefinitely until the lock is acquired.
  2. While inside the block, you will exclusively own the advisory lock.
  3. The lock will be released after your block ends, even if an exception is raised in the block.

This is usually required if there is no suitable database row to lock on.

Example

You want to generate a...

Vortrag: Content Security Policy: Eine Einführung

Grundidee

CSP hat zum Ziel einen Browser-seitigen Mechanismus zu schaffen um einige Angriffe auf Webseiten zu verhindern, hauptsächlich XSS-Angriffe.

Einschub: Was ist XSS?

XSS = Cross Site Scripting. Passiert wenn ein User ungefiltertes HTML in die Webseite einfügen kann.

<div class="comment">
  Danke für den interessanten Beitrag! <script>alert('you have been hacked')</script>
</div>

Rails löst das Problem weitgehend, aber

  • Programmierfehler weiter möglich
  • manchmal Sicherheitslücken in Gems oder Rails

Lösungsid...

The State of Ruby 3 Typing | Square Corner Blog

We're pleased to announce Ruby 3’s new language for type signatures, RBS. One of the long-stated goals for Ruby 3 has been to add type checking tooling. After much discussion with Matz and the Ruby committer team, we decided to take the incremental step of adding a foundational type signature language called “RBS,” which will ship with Ruby 3 along with signatures for the stdlib. RBS command line tooling will also ship with Ruby 3, so you can generate signatures for your own Ruby code.

Ruby 3 is coming, and it will have optional type sign...

Introducing GoodJob 1.0, a new Postgres-based, multithreaded, ActiveJob backend for Ruby on Rails

GoodJob is a new background worker gem. It's compatible with ActiveJob.

We're huge fans of Sidekiq for its stability and features. One advantage of GoodJob over Sidekiq is that GoodJob doesn't require Redis. So in cases where you don't have Redis or don't want to pay for a Redis HA quorum node, this might be an alternative worth checking out.

Fixing wall of warnings: already initialized constant Etc::PC_SYMLINK_MAX

These warnings are printed when the etc Gem is installed, while etc is also included in Ruby. Fix with:

gem uninstall etc

Automatically validating dependency licenses with License Finder

"Open-source software (OSS) is great. Anyone can use virtually any open-source code in their projects."

Well, it depends. Licenses can make things difficult, especially when you are developing closed-source software. Since some OSS licenses even require the employing application to be open-sourced as well (looking at you, GPL), you cannot use such software in a closed-source project.

To be sure on this, we have developed a project-level integration of Pivotal's excellent [license_finder](https:/...

How to prevent Nokogiri from fixing invalid HTML

Nokogiri is great. It will even fix invalid HTML for you, like a browser would (e.g. move block elements out of parents which are specified to not allow them).

>> Nokogiri::HTML.fragment("<h1><p>foo</p><span>bar</span></h1>").to_s
=> "<h1></h1><p>foo</p><span>bar</span>"

While this is mostly useful, browsers are actually fine with a bit of badly formatted HTML. And you don't want to be the one to blame when the SEO folks complain about an empty <h1>.

To avoid said behavior, use Nokogiri::XML instead of Nokogiri::HTML whe...