Ruby: Following redirects with the http gem ("httprb")

When making requests using the http gem you might want to automatically follow redirects to get the desired response. This is supported but not the default behavior.

You can do so by using the .follow method.
This follows redirects for the following status codes: 300, 301, 302, 303, 307, 308

response = HTTP.get('https://www.example.com/redirect')
response.status # => 302
response.uri.to_s # => "https://www.example.com/redirect"

response = HTTP.follow.get('https://www.example.com/redirect')
response.status # => 200
response....

Using rack-mini-profiler (with Unpoly)

Debugging performance issues in your Rails app can be a tough challenge.

To get more detailed insights consider using the rack-mini-profiler gem.

Setup with Unpoly

Add the following gems:

group :development do
  gem 'memory_profiler'
  gem 'rack-mini-profiler'
  gem 'stackprof'
end

Unpoly will interfere with the rack-mini-profiler widget, but configuring the following works okayish:

// rack-mini-profiler + unpoly
if (process...

Ruby: How to connect to a host with expired SSL certificate

If you need to make an HTTPS connection to a host which uses an expired certificate, do not disable certificate verifications entirely. Doing that enables e.g. man in the middle attacks.
If you accept only a single expired and known certificate, you are much less in trouble.

Setup

All the solutions described below use a verify_callback for the request's OpenSSL::X509::Store where you can specify a lambda to adjust its verification response.
Your callback must return either true or false and OpenSSL's verification result is...

List of handy Ruby scripts to transcode different file types (often by using GPT)

It's 2024 and we have tools like ffmpeg, imagemagick and GPT readily available. With them, it's easy to convert texts, images, audio and video clips into each other.

For the everyday use without any parameter tweaking I'm using a collection of tiny scripts in my ~/bin folder that can then be used as bash functions. And: It's faster to use the CLI than interacting with a website and cheaper to use the API than buying GPT plus.. :-)

Usage

  • text-to-image "parmiggiano cheese wedding cake, digital art"
  • `text-to-audio "Yesterday I ate ...

Use <input type="number"> for numeric form fields

Any form fields where users enter numbers should be an <input type="number">.

Numeric inputs have several benefits over <input type="text">:

  • On mobile or tablet devices, number fields show a special virtual keyboard that shows mostly digit buttons.
  • Decimal values will be formatted using the user's language settings.
    For example, German users will see 1,23 for <input type="number" value="1.23">.
  • Values in the JavaScript API or when submitting forms to the server will always use a point as decimal separator (i.e. "1.23" eve...

Bash: How to count and sort requests by IP from the access logs

Example

87.140.79.42 - - [23/Jan/2024:09:00:46 +0100] "GET /monitoring/pings/ HTTP/1.1" 200 814 "-" "Ruby"
87.140.79.42 - - [23/Jan/2024:09:00:46 +0100] "GET /monitoring/pings/ HTTP/1.1" 200 814 "-" "Ruby"
87.140.79.41 - - [23/Jan/2024:09:00:46 +0100] "GET /monitoring/pings/ HTTP/1.1" 200 814 "-" "Ruby"
87.140.79.42 - - [23/Jan/2024:09:00:46 +0100] "GET /monitoring/pings/ HTTP/1.1" 200 814 "-" "Ruby"

Goal

Count and sort the number of requests for a single IP address.

Bash Command

awk '{ print $1}' test.log | sort...

When loading Yaml contents in Ruby, use the :freeze argument to deep-freeze everything

Ruby methods which load from a Yaml file, like YAML.safe_load or YAML.safe_load_file, support passing freeze: true to deep-freeze the entire contents from the Yaml file.
This is available by default on Ruby 3.0 and newer. On older Rubies, you can install psych 3.2.0 or newer for :freeze support.

As an example, consider the following Yaml file:

---
message:
  - hello
  - universe
foo:
  bar:
    baz: "example"

We can now load it as usual, but pass freeze: true.

>> test = YAML.safe_load_file('example.yml', fre...

Maintaining custom application tasks in Rails

Here are some hints on best practices to maintain your tasks in larger projects.

Rake Tasks vs. Scripts

  • The Rails default is using rake tasks for your application tasks. These live in lib/tasks/*.
  • In case you want to avoid rake for your tasks and just use plain ruby scripts, consider lib/scripts/* as folder.

Keeping tasks slim

For readability and testing it's easier to keep your tasks slim.

Example:

lib/gitlab/maintenance_tasks/user_export.rb:

module Gitlab
  module MaintenanceTasks
    class UserExport
   ...

OpenAI TTS: How to generate audio samples with more than 4096 characters

OpenAI is currently limiting the Audio generating API endpoint to text bodies with a maximum of 4096 characters.
You can work around that limit by splitting the text into smaller fragments and stitch together the resulting mp3 files with a CLI tool like mp3wrap or ffmpeg.

Example Ruby Implementation

Usage

input_text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Mi eget mauris pharetra et ultrices neque."
output_mp3_path = Rails.root.join("tts/ipsum...

Transfer records to restore database entries (with Marshal)

If you ever need to restore exact records from one database to another, Marshal might come in handy.

Marshal.dump is part of the ruby core and available in all ruby versions without the need to install anything. This serializes complete ruby objects including id, object_id and all internal state.

Marshal.load deserializes a string to an object. A deserialized object cannot be saved to database directly as the the dumped object was not marked dirty, thus rails does not see the need to save it, even if the object is not present in...

Zeitwerk: How to collapse folders in Rails

All direct child directories of app are automatically added to the eager- and autoload paths. They do NOT create a module for namespacing. This is intuitive, since there normally is no module Model, or module Controller. If you want to add a new base directory, there's no additional config needed.

Example

app
├── controllers
├── helpers
├── inputs # No config needed 
├── mailers
├── models
├── uploaders # No config needed
├── util # No config needed
└── workers # No config needed

Sometimes it's handy to group files wit...

Solving "TypeError (nil can't be coerced into Integer)" in the Rails console / IRB

On the Rails console, assigning an object to a variable can lead to this strange error (without stacktrace):

irb > recipient = Recipient.find(123)
Traceback (most recent call last):
TypeError (nil can't be coerced into Integer)
irb > recipient
#<Recipient ...

The error is only in the output – the assignment is working. It only occurs when using the --nomultiline option, and thus [only with IRB 1.2.0+ and before Ruby 3](https://github.com/makandra/geordi/blob...

Ruby: `extend` extends the singleton class's inheritance chain

In the discussion of the difference between include and extend in Ruby, there is a misconception that extend would add methods to the singleton class of a ruby object as stated in many posts on this topic. But in fact, it is added to the ancestors chain of the singleton class! Even though it is technically not the same, practically this can be considered the same in most use cases.

Example

This means, that we are able to overwrite these methods or call the parent version with super depending in which order and in whi...

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

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: