Minidusen: Filtering associated records
Minidusen lets you find text in associated records.
Assume the following model where a Contact
record may be associated with a Group
record:
class Contact < ApplicationRecord
belongs_to :group
validates_presence_of :name, :street, :city, :email
end
class Group < ApplicationRecord
has_many :contacts
validates_presence_of :name
end
We can filter contacts by their group name by joining the groups
table and filtering on a joined column.
Note how the joined column is qualified as groups.name
(rather than just `na...
Show/Hide Rubocop marking in RubyMine
If you have installed Rubocop in your project, RubyMine can show you Rubocop violations immediately in your editor. You probably already know this feature.
Example
Enable/Disable marking
If your RubyMine does not show you any violations, although there are some, you may have to enable the setting first.
To do so, open Navigate -> Search Everywhere -> Actions (Or use the shortcut CTRL + SHIFT + A
) and type in "rubocop", then you should see some...
How to configure file watchers in RubyMine
Installation
You need to install the official plugin, it is not bundled with RubyMine by default.
Example: Setup a watcher to verify rubocop integrity
First, open Settings -> Tools -> File Watchers. Then, configure rubocop to check every change to the VCS:
Note that the "program" argument must be part of your $PATH
. I worked around this constraint by using b
as a shim for bundle exec
.
Resources
- [File watchers documen...
Convert curl commands to ruby code
curl-to-ruby is a handy tool that converts your curl
command to ruby code that uses the Net::HTTP library.
Example
curl -X POST -d
"grant_type=password&email=email&password=password"
localhost:3000/oauth/token
will output to:
require 'net/http'
require 'uri'
uri = URI.parse("http://localhost:3000/oauth/token")
request = Net::HTTP::Post.new(uri)
request.set_form_data(
"email" => "email",
"grant_type" => "password",
"password" => "password",
)
req_options =...
Using ffmpeg as a HLS streaming server
A practical and detailed walk-through tutorial on using ffmpeg for live-streaming HLS, filled with real-world examples.
- Using FFmpeg as a HLS streaming server (Part 1) – HLS Basics
- Using FFmpeg as a HLS streaming server (Part 2) – Enhanced HLS Segmentation
- Using FFmpeg as a HLS streaming server (Part 3) – Multiple Bitrates
- Using FFmpeg as a HLS streaming server (Part 4) – Multiple Video Resolutions
- Using FFmpeg as a HLS streaming server (Part 5) – Folder Structure
- Using FFmpeg as a HLS streaming server (Part 6) – Independent Seg...
Tailwind versus BEM
The linked article compares two approaches for writing CSS:
- A component library (like BEM)
- Utility classes (like Tailwind)
It's good to know the pros and cons of each approach. Although we default to BEM, you might encounter a utility approach in a client project.
Terminator: do not broadcast to other windows
Terminator has a cool feature that allows you to split your terminal into many panels and type in all of them at the same time. It's called broadcasting and can be enabled by pressing Alt+a
(and disabled by Alt+o
).
However, in some circumstances it will also be broadcasted to other running instances of Terminator. This probably is not what you want and could be very dangerous (e.g. if you're logged in to a production server in a terminal that is on another workspace).
To prevent the broadcast from affecting other windows, go to `Prefer...
IIFEs in Coffeescript
In JavaScript we often use Immediately Invoked Function Expessions (or IIFEs) to prevent local variables from bleeding into an outside scope:
(function() {
var foo = "value"; // foo is scoped to this IIFE
})();
In Coffeescript an IIFE looks like this:
(->
foo = "value" # foo is scoped to this IIFE
)()
There is also a shorthand syntax with do
:
do ->
foo = "value" # foo is scoped to this IIFE
You can also use do
with arguments t...
Ruby: Comparing a string or regex with another string
In Rubocop you might notice the cop Style/CaseEquality
for e.g. this example:
def foo(expected, actual)
expected === actual
end
In case expected
is a Regex, it suggests to change it to the following pattern:
def foo(expected, actual)
expected.match?(actual)
end
In case expected
is a Regex or a String, you need to keep ===
. Otherwise the actual
expression is always converted to a regular expression.
# For expected === actual
foo('Test(s)', 'Test(s)') #=> true
# For expected.match?(actual)
foo('Test(...
Passive event listeners may speed up your scroll and touch events
Scroll and touch event listeners tend to be computationally expensive as they are triggered very often. Every time the event is fired, the browser needs to wait for the event to be processed before continuing - the event could prevent the default behavior. Luckily there is a concept called passive event listeners which is supported by all modern browsers.
Below are the key parts quoted from WICG's explainer on passive event listeners. See [this demo video](https://www.youtube.com/watch?v=NPM6172...
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
.
...
Manage Linux services on the command line (Ubuntu)
Ubuntu 18.04 uses systemd
to manage services.
There are basically two commands for listing all services and manipulating the state of a certain service: service
and systemctl
:
-
service
manages System V init scripts -
systemctl
controls the state of the systemd system and service manager. It is backwards compatible to System V and includes the System V services
Therefore I prefer to use systemctl
.
See which services are there
>systemctl list-units -a --type=service
UNIT LOAD ...
HTML file inputs support picking directories
HTML's <input type="file">
accepts a single file. You can allow multiple files via <input type="file" multiple>
.
But sometimes, selecting multiple files is not enough and can be cumbersome for the user. Enter webkitdirectory
:
<input type="file" webkitdirectory multiple>
Using webkitdirectory
switches the browser's file picker to select a directory. All files inside that directory, and inside any nested subdirectories, will be selected for the file input.
This can be useful when users want to upload all files from a nested dire...
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.
- Go to a new "ci" branch:
git checkout -b ci
- Update gemika to version >= 0.5.0 in all your Gemfiles.
- Have gemika generate a Github Actions workflow definition by running
mkdir -p .github/workflows; bundle exec rake gemika:generate_github_actions_workflow > .github/workf...
How to downgrade Google Chrome in Ubuntu
If you're experiencing problems with your Google Chrome installation after an update, it might help downgrading Chrome to check if the problem disappears. Keep in mind though that running outdated software, especially web browsers, is in most cases not a good idea. Please verify periodically if you still need to run the old version or if an even more recently updated version fixes the problems introduced in your version.
Here's how to get old versions of Chrome for your Ubuntu installation:
First, go to [UbuntuUpdates](https://www.ubuntuup...
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...
VCR: Alternative way of mocking remote APIs
If you need to test interaction with a remote API, check out the VCR gem as an alternative to Webmock or stubbing hell.
The idea behind VCR is that is performs real HTTP requests and logs the interaction in a .yml file. When you run the test again, requests and responses are stubbed from the log and the test can run offline.
It's a great way to mock network requests to an external service without going through the pain of log...
Error when deploying 1.8.7 app: "NoMethodError: undefined method `select!' for ["zlib@openssh.com", "zlib"]:Array"
Fix: downgrade net-ssh
to version 2.9.1.
PostgreSQL: Importing dumps created with newer versions
When loading a database dump created with pg_dump
into your database, you might run into an error like
pg_restore: error: unsupported version (1.15) in file header
This is because your local pg_restore
version is too old to match the format created by pg_dump
. The version of the PostgreSQL server doesn't matter here.
For example, the official Ubuntu 20.04 sources include only PostgreSQL 12, so your pg_restore
version will also be v12. Ubuntu 22.04 includes version 14 in its sources.
Both seem to be incompatible with dumps ...
Rails: How to restore a postgres dump from the past
It sometimes happen that a database dump, that would want to insert into your development database, does not match the current schema of the database. This often happens when you have an old dump, but your current setup is up to date with the the master.
Hint: In most cases it is sufficient to delete and recreate the local database in order to import the dump. If any problems occur, proceed as follows:
1. Figure out the original migration status of the dumpfile
- Convert your dump to plaintext: `pg_restore -f some.dump > some.dump....
Security issues with hash conditions in Rails 2 and Rails 3
Find conditions for scopes can be given either as an array (:conditions => ['state = ?', 'draft']
) or a hash (:conditions => { 'state' => 'draft' }
). The later is nicer to read, but has horrible security implications in some versions of Ruby on Rails.
Affected versions
Version | Affected? | Remedy |
---|---|---|
2.3.18 | yes | Use chain_safely workaround |
3.0.20 | no | ... |
Where to find .desktop files on Ubuntu
.desktop
files define launchers for applications installed on your machine. They specify the command that will be executed when launched, icons, titles, etc. There are two directories in which these files are stored:
# basic installation
/usr/share/applications
# installed via snap
/var/lib/snapd/desktop/applications/
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...