How to open files from better_errors with RubyMine on Linux
I recently noticed that better_errors
allows you to to open files from within your favorite editor. However it was not so easy to get rubymine://
links to work on Gnome/Linux. Here is how it finally worked for me:
Step 1: Add a Desktop launcher
Add this file to ~/.local/share/applications/rubymine.desktop
:
[Desktop Entry]
Version=1.0
T...
Preventing users from uploading malicious content
When you allow file uploads in your app, a user might upload content that hurts other users.
Our primary concern here is users uploading .html
or .svg
files that can run JavaScript and possibly hijack another user's session.
A secondary concern is that malicious users can upload executables (like an .exe
or .scr
file) and use your server to distribute it. However, modern operating systems usually warn before executing files that were downloaded from t...
We have deprecated Rack::SteadyETag
Rack::SteadyETag
was a Rack middleware that generates the same default ETag
for responses that only differ in XOR-masked CSRF tokens or CSP nonces.
We have deprecated Rack::SteadyETag. We instead recommend reconfiguring your Rails app so two requests to the same resource produce the same HTML for a given user.
Rails: Fixing ETags that never match
Every Rails response has a default ETag
header. In theory this would enable caching for multiple requests to the same resource. Unfortunately the default ETags produced by Rails are effectively random, meaning they can never match a future request.
Understanding ETags
When your Rails app responds with ETag
headers, future requests to the same URL can be answered with an empty response if the underlying content ha...
ASDF: A Version Manager To Rule Them All
tl;dr
asdf
allows you to manage multiple runtime versions with a single CLI tool and is backwards compatible by supporting existing config files, like e.g..nvmrc
or.ruby-version
.
Getting Started
- Disable rbenv
1.1 Delete or comment outsource /home/$user/.rbenvrc
in~/.profile
1.2 Delete or comment oureval "$(rbenv init -)"
in~/.bashrc
or~/.zshrc
1.3 To take effect you may have to restart your shell or log out and log in again from your current linux session - Install asdf by following the official ...
CSP: strict-dynamic
tl;dr
The
strict-dynamic
source list keyword allows you to simplify your CSP policy by favoring hashes and nonces over domain host lists.The key super power of
strict-dynamic
is that it will allow to load additional scripts via non-"parser-inserted" script elements.
For unsupported browsers, your script can be made backwards compatible by doing something like this:
script-src 'nonce-rAnd0m' 'strict-dynamic' https: 'self'
default-s...
Sidekiq 7: Rate limiting with capsules
Sidekiq 7 adds a new feature called capsules.
Use cases:
- a
chrome
queue limited to1
for e.g. PDF processing to not overload the application server - an
api
queue, that limits a queue to2
to protect the API server from too many requests in parallel
Example:
Sidekiq.configure_server do |config|
# Edits the default capsule
config.queues = %w[critical default low]
config.concurrency = 5
# Define a new capsule which ...
ActiveRecord::Relation#merge overwrites existing conditions on the same column
In Ruby on Rails ActiveRecord::Relation#merge
overwrites existing conditions on the same column. This may cause the relation to select more records than expected:
authorized_users = User.where(id: [1, 2])
filtered_users = User.where(id: [2, 3])
authorized_users.merge(filtered_users).to_sql
# => SELECT * FROM users WHERE id IN (2, 3)
The merged relation select the users (2, 3)
, although we are only allowed to see (1, 2)
. The merged result should be (2)
.
This card explores various workarounds to combine two scopes so t...
Rubymine: Configure CTRL + ALT + SHIFT + c to work with "Test Source Roots"
To navigate between test and test subject Rubymine requires you to set the test root sources as Test Sources Root.
In case you are using the keyboard shortcut "CTRL + ALT + SHIFT + c" to copy the reference path + you have set the "Test Sources Root" for your test folders, you might consider setting this keyboard to "Copy From Repository Root". This will return the path `spec/foo_spec....
Rails cache connection settings
If you're using a Redis cache in Rails (e.g. :redis_cache_store
), it's possible to configure additional parameters for your Redis connection.
Example config for Rails 7.2
config.cache_store = :redis_cache_store, {
pool: { timeout: 0.5 },
read_timeout: 0.2, # default 1 second
write_timeout: 0.2, # default 1 second
# Attempt two reconnects with some wait time in between
reconnect_attempts: [1, 5], # default `1` attempt in Redis 5+
url: REDIS_URL,
error_handler: ->(method:, returning:, exception:) {
Sentry.captur...
Rails: Assigning associations via HTML forms
Let's say we have posts with an attribute title
that is mandatory.
Our example feature request is to tag these posts with a limited number of tags. The following chapters explain different approaches in Rails, how you can assign such an association via HTML forms. In most cases you want to use Option 4 with assignable values.
The basic setup for all options looks like this:
config/routes.rb
Rails.application.routes.draw do
root "posts#index"
resources :posts, except: [:show, :destroy]
end
**db/migrate/...
How to exclusively lock file access in ruby
We will achieve this by creating a block accepting method to optionally create and then lock a .lock
File of the underlying accessed file.
Why create a .lock
file?
- The main advantage of creating a
.lock
file is that#flock
might block some operations and require the index node of the file to be consistent. Some operations might change that index node. - In some cases it might also be convenient to just read/write the lock file first and update the other file afterwards or vice versa, such that breaking of a process does not...
Issue Checklist Template
This is a checklist I use to work on issues. For this purpose I extracted several cards related to the makandra process and ported them into a check list and refined that over time a little bit.
This task list is divided by the Gate keeping process in the following steps:
1. Starting a new feature
2. Working on the issue
3. Finishing a feature
4. After Review
Here are some ti...
Rails Partials
Rails partials have a lot of "hidden" features and this card describes some non-obvious usages of Rails Partials.
Rendering a basic partial
The most basic way to render a partial:
render partial: 'partial'
This will render a _partial.html.erb
file. Notice how all partials need to be prefixed with _.
It's possible to define local variables that are only defined in the partial template.
# _weather.html.erb
<h1>The weather is <%= condition %></h1>
# index.html.erb
render partial: 'weather', locals: { condition: ...
How to turn images into inline attachments in emails
Not all email clients support external images in all situations, e.g. an image within a link. In some cases, a viable workaround is to turn your images into inline attachments.
Note
Rails provides a simple mechanism to achieve this:
This documentation makes it look like you have to care about these attachments in two places. You have to create the attachment in t...
git: find the version of a gem that releases a certain commit
Sometimes I ran across a GitHub merge request of a gem where it was not completely obvious in which version the change was released. This might be the case for a bugfix PR that you want to add to your project.
Git can help you to find the next git tag that was set in the branch. This usually has the name of the version in it (as the rake release
task automatically creates a git tag during release).
git name-rev --tags <commit ref>
Note
The more commonly used
git describe
command will return the last tag before a c...
Signed URLs with Ruby on Rails
Using ActiveRecord's #signed_id
and .find_signed
methods you can create URLs that expire after some time. No conditionals or additional database columns required.
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...
Bookmarklet: cards Markup Link Bookmarklet
The cards editor has a feature "Cite other card" to create links to other cards in the same deck as mardown links.
If you want to reference a card from a different deck, this bookmarklet might be useful:
javascript:(function () {
const doAlert = () => { alert("Maybe not a makandra card?") };
let cardsPathPattern = /(\/[\w-]+\/\d+)-.+/;
if (window.location.pathname.match(cardsPathPattern)) {
let currentPath = window.location.pathname.match(cardsPathPattern)[1];
let title = document.querySelector('h1.note--title')?.textCon...
A modern approach to SVG icons
You have some SVG files you want to use as icons on your website. How would you embed them?
Common options are:
- Use them with an image:
<img src='path-to-icon.svg'>
- Embed them inline with
<svg>$ICON</svg>
- Embed them using CSS and
background-image: url(path-to-icon.svg)
or evenbackground-image: url(data:$ICON)
. - Build your own icon font.
All of these have drawbacks:
- Image and
background-image
do not allow to recolor the image using CSS. - Inline-
<svg>
are unnecessary work for the server and are...
Using path aliases in esbuild
In esbuild, you usually import other files using relative paths:
import './some-related-module'
import `../../utils/some-utility-module`
import `../../../css/some-css.sass`
This is totally fine if you import closely related files, but a bit clunky when you're trying to import some "global" module, like a utility module. When moving a file, your imports also need to change.
To get around this, esbuild support a mechanism first introduced in TypeScript called "path aliases". It works like this:
First, you create a file called `js...
Chrome DevTools: Treasure (Overview)
tl;dr
The Chrome DevTools are a neat collection of tools for the daily work as a web developer. If you're lucky, you'll maybe find some handy stuff in here.
Analysing
Breakpoints
- [Breakpoints on HTML Elements](https://makandracards.com/makandra/517982-chrome-devtools...
GitLab: Git alias for creating a merge request on push
Git allows you to set push options when pushing a branch to the remote.
You can use this to build an alias that automatically pushes a branch and creates a merge request for it.
Put this in your ~/.gitconfig
in the [alias]
section:
mr = push origin HEAD -o merge_request.create -o merge_request.draft
Now you can do git mr
and a draft merge request will be created.
Target branch is your project's default branch, i.e. main
or master
.
To specify a different target branch, add -o merge_request.target=other-branch
.
[There...
Debug flaky tests with an Unpoly observeDelay
The problem
Unpoly's [up-observe]
, [up-autosubmit]
and [up-validate]
as well as their programmatic variants up.observe()
and up.autosubmit()
are a nightmare for integration tests.
Tests are usually much faster than the configured up.form.config.observeDelay
. Therefore, it may happen that you already entered something into the next field before unpoly updates that field with a server response, discarding your changes.
The steps I wait for active ajax requests to complete
(if configured) and capybara-lockstep can catch some ...