Heads up: network requests `Kernel#open` are not mocked with VCR
We usually rely on VCR and WebMock to prevent any real network connection when running our unit tests.
This is not entirely true: They are both limited to a set of HTTP libraries listed below (as of 2022). Direct calls to Kernel#open
or OpenURI#open_uri
are not mocked and will trigger real network requests even in tests. This might bite you e.g. in [older versions of CarrierWave](https://github.com/carrierwaveuploader/carrierwave/blob/0.11-stable/lib/carrierwave/upl...
Git: Restore
tl;dr
git checkout
is the swiss army of git commands. If you prefer a semantically more meaningful command for restoring tasks, usegit restore
instead.With this command you can ...
- ... do unstaging -
git restore --staged
- ... discard staged changes -
git restore --staged --worktree
- ... discard unstaged changes -
git restore
- ... restore deleted files -
git restore
- ... restore historic versions -
git restore --source
- ... recreate merge conflicts -
git restore --merge
- ... specifiy...
RubyMine: Find and Replace with Regex (Capture Groups and Backreferences)
tl;dr
In RubyMine you can use find and replace with capture groups
(.*?)
and backreferences$1
(if you have several groups:$[Capture-Group ID]
).
Named captures(?<text>.*)
are also supported.
Examples
Replace double quotes with single quotes
If you want to replace double quotes with single quotes, replacing every "
with a '
is prone to errors. Regular expressions can help you out here.
- Open find and replace
- Activate the regex mode (click on the
.*
icon next to the "find" field). - Fill in f...
Prefer using Dir.mktmpdir when dealing with temporary directories in Ruby
Ruby's standard library includes a class for creating temporary directories. Similar to Tempfile it creates a unique directory name.
Note:
- You need to use a block or take care of the cleanup manually
- You can create a prefix and suffix e.g.
Dir.mktmpdir(['foo', 'bar']) => /tmp/foo20220912-14561-3g93n1bar
- You can choose a different base directory than
Dir.tmpdir
e.g. `Dir.mktmpdir('foo', Rails.root.join('tmp')) => /home/user/rails_example/tmp/foo20220912-14...
Ruby and Rails: Debugging a Memory Leak
A memory leak is an unintentional, uncontrolled, and unending increase in memory usage. No matter how small, eventually, a leak will cause your process to run out of memory and crash.
If you have learned about a memory leak, looking at the number of Ruby objects by type can help you track it down:
> pp ObjectSpace.count_objects
{:TOTAL=>77855,
:FREE=>4526,
:T_OBJECT=>373,
:T_CLASS=>708,
:T_MODULE=>44,
:T_FLOAT=>4,
:T_STRING=>65685,
:T_REGEXP=>137,
:T_ARRAY=>984,
:T_HASH=>87,
:T_STRUCT=>12,
:T_BIGNUM=>2,
:T_FILE=>3,
:T_D...
Converting SVG to other vector formats without Inkscape
If you need to convert an SVG source to PS or EPS, the most common suggestion on the interwebs is to use Inkscape from the commandline.
Inkscape is a fairly resource-heavy tool with lots of dependencies. A great alternative for converting is CairoSVG.
CairoSVG is available on most Linux distros through their package management systems, e.g. apt install cairosvg
on Ubuntu.
It has few dependencies (most importantly Python 3 and some related packages, but really not much)...
Creating a Rails application in a single file
Greg Molnar has written a neat article about creating a single-file Rails app.
This is not meant for production use but can be useful to try things out, e.g. when hunting down a bug or embedding a Rails app into the tests of a gem.
What you do is basically:
- Put everything (gems, application config, database migrations, models, controllers) into a single
.ru
file, likeapp.ru
. - Run it via
rackup app.ru
. (Hint: if your file is calledconfig.ru
, you can just run `rac...
Generating and streaming ZIP archives on the fly
When your Rails application offers downloading a bunch of files as ZIP archive, you basically have two options:
- Write a ZIP file to disk and send it as a download to the user.
- Generate a ZIP archive on the fly while streaming it in chunks to the user.
This card is about option 2, and it is actually fairly easy to set up.
We are using this to generate ZIP archives with lots of files (500k+) on the fly, and it works like a charm.
Why stream downloads?
Offering downloads of large archives can be cumbersome:
- It takes time to b...
A short overview of common design patterns implemented within Rails
The linked content includes a few design patterns implemented with Ruby on Rails.
What is the card indented to achieve?
- You can use the pattern names for code reviews, so all parties know with only a few words which change is requested. Example: "Please use a form object here"
- You can learn about new code patterns
- You should read the sections "Advantages of using design patterns" and "Disadvantages of using design patterns in a wrong way", since design patterns do not replace good code
Included Design Patterns: Service, Value objec...
makandra tech survey - results
These are the results of the "personal tech stack survey". I've included only the most popular mentions, maybe it can help you find one or two useful tools for your own usage.
Desktop environment
pie title Desktop environment
"Gnome" : 16
"i3": 2
"sway": 2
"awesome": 1
"bspwm": 1
"mate": 1
"xfce": 1
Gnome dominates (unsuprising, it's the Ubuntu default), but quite a few people use tiling window managers, most popular i3 and the mostly i3-compatible [sway](https://swaywm....
Fix for mysql2 error "Incorrect MySQL client library version! This gem was compiled for x.x.x but the client library is y.y.y."
This should be fixed in the latest LTS-branches of our mysql2 fork, 0.2.x-lts and 0.3.x-lts.
Use
gem 'mysql2', git: 'https://github.com/makandra/mysql2', branch: '0.2.x-lts' # for Rails 2.x
gem 'mysql2', git: 'https://github.com/makandra/mysql2', branch: '0.3.x-lts' # for Rails 3.x
in your Gemfile, and do a
bundle update mysql2
Background
mysql2 used to check that the client library used at runtime actually matches the one it was compiled against. However, at least on Ubunt...
Double loading issue with Ruby default gems
Ruby includes many standard gems that are bundled into the Ruby installation. Here is an example for the gem strscan
that will be displayed as default
:
gem list strscan
*** LOCAL GEMS ***
strscan (default: 3.0.1)
It is still possible to have newer version of a gem installed beside the default version:
gem install strscan
Fetching strscan-3.0.3.gem
Building native extensions. This could take a while...
Successfully installed strscan-3.0.3
1 gem installed
gem list strscan
*** LOC...
You are not using filter_map often enough
Somewhat regularly, you will need to filter a list down to some items and then map them to another value.
You can of course chain map
and compact
, or select
/filter
and map
, but Ruby 2.7 introduced a method for this exact purpose: filter_map
.
So instead of
>> [1, 2, 3, 4, 5, 6].map { |i| i * 2 if i.even? }.compact
=> [4, 8, 12]
or
>> [1, 2, 3, 4, 5, 6].select(&:even?).map { |i| i * 2 }
=> [4, 8, 12]
you can just do
>> [1,...
Capybara: Most okayest helper to download and inspect files
Testing file download links in an end-to-end test can be painful, especially with Selenium.
The attached download_helpers.rb
provides a download_link
method for your Capybara tests. It returns a hash describing the download's response:
details = download_link('Download report')
details[:disposition] # => 'attachment' or 'inline'
details[:filename] # => 'report.txt'
details[:text] # => file content as string
details[:content_type] # => 'text/plain'
Features
Compared to [other approaches](...
JavaScript: New Features in ES2021
tl;dr
With ES2021 you now can use
str.replaceAll()
,Promise.any()
, logical assignment operators, numeric separators andWeakRef
on all major browsers except IE11.
replaceAll
JavaScript's replace(searchValue, replaceValueOrFn)
by default replaces only the first match of a given String or RegExp.
When supplying a RegExp as the searchValue argument, you can specify the g
("global") modifier, but you have to remember doing that, hence using replace
when you expect global replacement is prone to errors.
When supplying st...
net-ssh and openssl-3.0.0
You'll need openssl-3 or newer for servers running 22.04
Ruby version 3.1
uses by default the gem openssl-3.0.0
. This can cause issues with the gem net-ssh (6.1.0
). This is a known bug.
Typically this can cause an error while deploying an application with capistrano:
could not verify server signature (SSHKit::Runner::ExecuteError)
or
Ed25519::VerifyError: signature verification failed!
As temporary workaround add the following line to your Gemfile
:
gem 'openssl', ...
Use DatabaseCleaner with multiple test databases
There is a way to use multiple databases in Rails.
You may have asked yourself how you're able to keep your test databases clean, if you're running multiple databases with full read and write access at the same time. This is especially useful when migrating old/existing databases into a new(er) one.
Your database.yml
may look like this:
default: &default
adapter: postgresql
encoding: unicode
username: <%= ENV['DATABASE_USER'] %>
host: <%= ENV['DATABASE...
Gem development: recommended gem metadata
The gemspec for gems allows to add metadata to your gem, some of which have a special meaning and are helpful for users.
You can provide links to your Github bugtracker or changelog file that are then used on the rubygems page of your gem (in the sidebar, e.g. see gem page of consul).
Here are some keys that should be filled:
Gem::Specification.new do |s|
s.name = 'my-gem'
s.homepage = 'https://github.com/makandra/my-gem'
s.metadata = {
'source_code_uri' => s.homepage,
'bug_tracker...
How to get information about a gem (via CLI or at runtime from Ruby)
When you need information about a gem (like version(s) or install path(s)), you can use the gem
binary from the command line, or the Gem
API inside a ruby process at runtime.
gem
binary (in a terminal)
You can get some information about a gem by running gem info <gem name>
in your terminal.
Example:
$ gem info irb
*** LOCAL GEMS ***
irb (1.4.1, 1.3.5)
Author: Keiju ISHITSUKA
Homepage: https://github.com/ruby/irb
Licenses: Ruby, BSD-2-Clause
Installed at (1.4.1): /home/arne/.rbenv/versions/3.0.3/lib/ruby/g...
jeremyevans/ruby-warning: Add custom processing for warnings
ruby-warning adds custom processing for warnings, including the ability to ignore specific warning messages, ignore warnings in specific files/directories, include backtraces with warnings, treat warnings as errors, deduplicate warnings, and add custom handling for all warnings in specific files/directories.
This tool can precisely silence deprecation warnings.
While you should fix deprecations in your application, ruby-warning is handy to silence those warnings that you cannot fix. E.g. when they originate from libraries that you ca...
Version 5 of the Ruby Redis gem removes Redis.current
Redis.current
will be removed without replacement in redis-rb
5.0.
Version 4.6.0 adds deprecation warnings for Redis.current
and Redis.current=
:
`Redis.current=` is deprecated and will be removed in 5.0.
If your application still uses Redis.current
, you can only fix it by no longer using it. Here is how.
Redis.new when you need it
You can easily instantiate a Redis
client when you need it.
There is probably already a constant like REDIS_URL
that you use to configure Sidekiq or similar. So just use that one.
``...
Integrating ESLint
Introduction
To ensure a consistent code style for JavaScript code, we use ESLint. The workflow is similar to integrating rubocop for Ruby code.
1. Adding the gem to an existing code base
You can add the following lines to your package.json
under devDependencies
:
"devDependencies": {
"@eslint/js": "x",
"@stylistic/eslint-plugin": "x",
"eslint": "x",
"eslint-plugin-import": "x",
"globals": "x",
}
...
How to add esbuild to the rails asset pipeline
This are the steps I needed to do to add esbuild to an application that used the vanilla rails asset pipeline with sprockets before.
Preparations
- update Sprockets to version 4
- add a
.nvmrc
with your preferred node version (and install it) - add gems
jsbundling-rails
andforeman
to yourGemfile
:gem 'jsbundling-rails' group :development, :test do gem 'foreman' # ... end
bundle install
- run
bin/rails javascript:install:esbuild
in a console to prepare esbuild. - run `yarn instal...
Understanding Ruby's def keyword
This StackOverflow question about nested function definitions in Ruby imparts a good understanding of Ruby's def
.