Today I learned
Read about some cool stuff.
PostgreSQL Database Dump&Restore
Jan 15, 2026

When you need to create a database dump and restore it (especially for a new environment or migrating an app), it's worth asking yourself a few important questions before you start:

  • Which database(s) do I need to back up?
  • Where are multimedia files stored? (Are they kept on disk, in S3, or another external service?)
  • Does the dump alone capture all critical application data, or do I need additional steps?

These considerations help prevent surprises and make the restoration process much smoother.

Recently, I did my first PostgreSQL database dump and restore. Here’s what I learned and what you should keep in mind:


Database Dump

To back up the PostgreSQL database, I used the pg_dump command with the following setup:

pg_dump -h localhost -U db_user -d db_name -F c --no-owner -f ~/dump_$(date +%Y%m%d).dump
  • The --no-owner flag is very important—it prevents warnings during the restoration. Without it, the dump records who owns each table (for example, user dev), and this can cause errors like role 'dev' does not exist if you restore on another machine.
  • The -F c flag makes a compressed, "custom" format dump, which is smaller and allows for selectively restoring data.

Restore and Application Data

To restore the backup, I first created a new database:

createdb new_database
pg_restore -d new_database ~/dump_20260114.dump

This part was straightforward. After restoring, make sure to verify your application—check if all data is in place and working.

What About Media Files?

When I checked the admin panel in my app, I noticed that images were missing. This is because:

  • In our app, we don't use S3; all files are stored locally on disk using Active Storage.
  • The database dump only contains metadata about the files (active_storage_blobs and active_storage_attachments tables).
  • The files themselves are separate and must be copied manually.

Therefore, in my case, I also had to back up the storage folder in addition to the database dump. Once I did that, everything worked as expected!

Efficiently Transferring Large Folders

Our storage folder was about 8GB, and the server had very little free space. I couldn’t create an archive on the server first. Luckily, there's a way to compress and download the folder directly (without saving the archive locally on the server):

ssh server "cd /path/to/app && tar czf - storage" > ~/Downloads/storage_backup.tar.gz
  • Here, tar czf - storage streams the archive straight to your local machine.

Resources for Further Reading:

- pg_dump documentation

- pg_restore documentation

- tar documentation


In summary:

Before dumping your database, think about all areas where your app stores data, especially multimedia. Back up both your database and any storage directories or external resources for a complete and functional restore.

How to run Mutant in your Rails project
Oct 20, 2025

Mutant is (as the author describes it) "an automated code review tool, with a side effect of producing semantic code coverage metrics."

Here's a straightforward example showing how to use Mutant within a Rails project - a solid foundation to begin exploring its features and the power of mutation testing in your codebase.

RAILS_ENV=test bundle exec mutant run -r ./config/environment.rb -j 1 --integration rspec \
  --usage opensource -- Class::Or::NameSpace::To::Mutate

Let's analyze what the individual parameters are responsible for:

RAILS_ENV=test

Don’t forget to set the correct environment for runing rails specs.

-r ./config/environment.rb
# or
--require ./config/environment.rb

Loads and initializes your application's code. The config/environment.rb file is the entry point of every Rails app.

-j 1
# or
--jobs 1

Limits concurrent jobs to one. This is a safe option for specs that aren't written with parallelism in mind or for databases (like SQLite) that aren't designed for concurrent access.

--integration rspec

rspec or minitest - depending on your test framework.

--usage opensource

opensource or commercial - depending on the chosen license.


You can also set these parameters using a YAML configuration file:

# in `.mutant.yml` file
---
environment_variables:
  RAILS_ENV: test
requires:
  - ./config/environment.rb
jobs: 1
integration:
  name: rspec
usage: opensource

Then you can simply run:

bundle exec mutant run Class::Or::NameSpace::To::Mutate
Easily install the latest version of gems from GitHub
Sep 11, 2025

You can use the "specific_install" RubyGems plugin to install gems directly from GitHub.

# first install the plugin
gem install specific_install

# then install a gem directly from a repo URL
gem specific_install https://github.com/example/cool_ruby_gem
Lazy enumerators in Ruby
Aug 22, 2025

The main differences between standard (eager) enumerators and lazy ones lie in how they process data through chains of enumerations. Standard enumerators handle this in a sequential manner, while lazy enumerators pass each value through the entire chain one by one.

def do_a(x)
  puts "Doing A with #{x}"
  x
end

def do_b(x)
  puts "Doing B with #{x}"
  x
end


result = (1..5)
  .map { do_a(it) }
  .map { do_b(it) }
  .take_while { it < 3 }
  .to_a

# Doing A with 1
# Doing A with 2
# Doing A with 3
# Doing A with 4
# Doing A with 5
# Doing B with 1
# Doing B with 2
# Doing B with 3
# Doing B with 4
# Doing B with 5

puts result.inspect # [1, 2]

# ----

result = (1..5)
  .lazy
  .map { do_a(it) }
  .map { do_b(it) }
  .take_while { it < 3 }
  .to_a

# Doing A with 1
# Doing B with 1
# Doing A with 2
# Doing B with 2
# Doing A with 3
# Doing B with 3

puts result.inspect # [1, 2]

There are three main benefits of using lazy enumerators:

  1. You can stop early. No need to process all the data if you've already gathered the required results. Methods like first and take_while are your friends here.
  2. They are CPU-efficient. By using enumerators like select, you can stop further processing of an item at any step of the chain.
  3. They are memory-efficient. They don't build intermediate arrays, so the data used in processing can be released right after handling the current item. This is especially useful when dealing with files or fetching data from URLs.
Ruby class deconstruction
Aug 21, 2025

Ruby class deconstruction is quite intuitive and essentially reuses array and hash deconstruction via the deconstruct and deconstruct_keys methods.

class Result
  attr_reader :success, :info

  def initialize(success:, info:)
    @success = success
    @info = info
  end

  def deconstruct
    [ @success, @info ]
  end

  def deconstruct_keys(*)
    { success:, info: }
  end
end

You can think of this as automatic type conversion before deconstruction.


There are two common ways of deconstructing in Ruby. One is using the rightward assignment operator =>.

result = Result.new(success: false, info: 'Not enough potatoes' )

result => x, y

puts x # false
puts y # Not enough potatoes

result => { info:, success: }

puts info # Not enough potatoes
puts success # false

The other is using pattern matching:

case result
in true, info
  puts "Success with info: #{info}"
in false, info
  puts "Failure with info: #{info}" # Failure with info: Not enough potatoes
end

case result
in success: true, info:
  puts "Success with info: #{info}"
in success: false, info:
  puts "Failure with info: #{info}" # Failure with info: Not enough potatoes
end

You can also match specific classes:

SomethingElse = Struct.new(:success, :info)
record = SomethingElse.new(true, 'All good')

case record
in Result[info:]
in SomethingElse(info:) # [] and () are interchangeable
  puts "info: #{info}" # info: All good
end

Ruby's built-in Struct supports deconstruction out of the box.


Since [] is just a regular Ruby method, you can design a clean and expressive interface with it:

class Container
  def self.[](value)
    new(value)
  end

  def initialize(value)
    @value = value
  end

  def deconstruct
    [ @value ]
  end
end

case Container[42]
in Container[value]
  puts "Value is: #{value}" # Value is: 42
end

This way, the initialization Container[42] and the deconstruction Container[value] share the same interface.

git rebase --onto
Aug 06, 2025

git rebase --onto allows you to change the base of a range of commits to a new starting point. It's especially useful when you want to move a feature branch to begin from a different commit, excluding unwanted or conflicting history - for example, when the original base branch has been rewritten or modified.

A---B---C---D---E  (main)
     \
      F---G---H  (feature)

To rebase feature (F, G, H) onto commit C:

git checkout feature
git rebase B --onto C
A---B---C---D---E  (main)
         \
          F---G---H  (feature)

You can think about this as:

Take feature commits after B and replay them onto C

# from
A---B---C---D---E  (main)
A---B---F---G---H  (feature)
    ↑   └────────
        Take this

# to

A---B---C---D---E  (main)
A---B---C---F---G---H  (feature)
        ↑   └────────
        Move onto C
Scanning Dotfiles to Prevent Secret Leaks
Aug 04, 2025

One of the most common security mistakes is accidentally exposing credentials to unauthorized individuals - whether by sharing files with others or mistakenly committing them to a repository. Because of this, many tools have been created to detect the presence of sensitive data. Below are two popular and proven solutions:

Gitleaks

# Scan the current directory for secrets
gitleaks dir -v

# Scan gir repository for secrets
gitleaks git -v

TruffleHog

# Scan the current filesystem directory
trufflehog filesystem .

# Scan the current Git repository
trufflehog git file://.

Regularly scanning dotfiles with tools like Gitleaks and TruffleHog helps detect and prevent leaking secrets into version control. This practice improves security and reduces the risk of exposing sensitive data. It's good idea to add them to your pre-commit hooks!

FactoryBot aliases and foreign keys
May 06, 2024

By default, FactoryBot assumes that {attribute}_id is the foreign key for ActiveRecord associations, which can lead to errors in other parts of your application that may be difficult to diagnose.

let!(:dog) {
  create(
    name: "Azor",
    tag: "Azor 000 000 000",
    tag_id: "#12",
  )
}

Dog.last.tag # nil
Dog.last.tag_id # nil

Since this is a common naming convention, it's better to avoid names like this and use more straightforward alternatives. For example tag_number.

More information here

Tailwind UI libraries
Apr 15, 2024

Some UI libraries for Tailwind that do not require installation. Just copy what you need and paste into your code:

ul. Powstańców Warszawy 5
15-129 Białystok
+48 668 842 999
CONTACT US