Split your parallel tests by execution time and keep execution logs up to date
Both knapsack
and parallel_tests
have the option to split groups by historic execution time. The required logs for this might be outdated since you manually have to update and push them into your repository.
The following card includes an option how you can keep them consistently up to date with no extra effort locally and/or remotely.
How to always split by execution logs
Parallel Tests
The parallel_tests
gem has the option flag `--group...
Git restore vs. reset for reverting previous revisions
The git doc states on the difference of these two commands:
- git-restore[1] is about restoring files in the working tree from either the index or another commit. This command does not update your branch. The command can also be used to restore files in the index from another commit.
- git-reset[1] is about updating your branch, moving the tip in order to add or remove commits from the branch. This operation changes the commit history.
git reset can also be used to restore th...
redirect_to and redirect
There are multiple ways to redirect URLs to a different URL in Rails, and they differ in small but important nuances.
Imagine you want to redirect the following url https://www.example.com/old_location?foo=bar
to https://www.example.com/new_location?foo=bar
.
Variant A
You can use ActionController::Redirecting#redirect_to
in a controller action
class SomeController < ActionController::Base
def old_location
redirect_to(new_location_url(params.permit(:foo)))
end
end
This will:
- It will redirect with a 302 st...
Do not use "permit!" for params
Rails' Strong Parameters enable you to allow only specific values from request params
to e.g. avoid mass assignment.
Usually, you say something like params.permit(:email, :password)
and any extra parameters would be ignored, e.g. when calling to_h
.
This is excellent and you should definitely use it.
What is permit!
and why is it dangerous?
However, there is also params.permit!
whic...
Capybara: How to find the focused element
Capybara allows you to filter elements that are focused.
page.find(:fillable_field, focused: true) # Filtering only fillable inputs for performance reasons
page.find(:xpath, '//*', focused: true) # Filter all fields
Legacy approach
In older version, it was possible to use the :focus
pseudo-class. This seems not to work in newer versions anymore.
find(':focus')
Postgres in Alpine docker container: sorting order might differ
In CI test runs I noticed that string sorting order changed after switching from a debian-based PostgreSQL docker image to one that is based on Alpine Linux.
Debian image sorting: bar Bar foo Foo
Alpine image sorting: Bar Foo bar foo
Explanation
Alpine Linux is a very slim linux distribution that results in small docker image sizes (roughly 100MB instead of 150MB), so it's a popular choice. However, it does not have all comman locales installed and does not use all locales that a user installs by default.
Postgres orders string co...
Use -webkit-line-clamp to natively truncate long (multi-line) texts with an ellipsis
Note: You won't need this for single lines of text. In this case it is better to just use the text-overflow
property: Use CSS "text-overflow" to truncate long texts
You can use -webkit-line-clamp
in your CSS/SASS to natively render an ellipsis (...
) after a specific amount of lines for a multi-line text in your HTML.
Earlier, it was necessary to implement JavaScript solutions like Superclamp.js to enable this because the browser support has been rather limited...
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:
- libvips is considerably faster and uses less memory.
- ImageMagick has a large attack surface that has repeatedly caused security incidents in the past (compare [ImageMagick CVEs](https://www....
RubyMine and Rubocop: Performing safe autocorrects on save
- Ctrl + Alt + S > search "rubocop on save"
- Under "Inspections", check the highlighted box on
rubocop -a
Caveat: This adds a little time overhead to saving. When you're editing many files at once (e.g. using "Replace All"), this may be inacceptable.
Balance your texts today with text-wrap: balance
So you have a heading that is just barely wider than the container it should fit into, and it wraps a single word to a new line and it's not really pretty?
Cry no more, for you can use text-wrap: balance
today to fix that. At least in some browsers.
When browsers encounter a text-wrapping element with text-wrap: balance
style, they will try breaking to a new line sooner, if it balances out the width of lines.
text-wrap: unset |
text-wrap: balance |
---|---|

- A specific package has a bug in a more recent version
- You want to ensure no...
Capo: putting <head> content into the right order
How you order elements in the <head> can have an effect on the (perceived) performance of the page.
This script helps you identify which elements are out of order.
Also available as a Chrome Extension. It shows the actual order of head elements, and suggests an optimal order for page performance.
How to pretty print all values in a Redis database
With this Ruby script you can print all values in a Redis database to your console (derived from this bash script).
Note: Do not run this command in production. This is for debugging purposes only.
def pretty_print_redis(redis)
redis.keys.each_with_object({}) do |key, hash|
type = redis.type(key)
hash[key] = case type
when 'string'
redis.get(key)
when 'hash'
redis.hgetall(key)
when 'list'
redis.lrange(key, 0, -1)
when 'set'
redis.smembers(...
Better HTML forms: use type, inputmode, enterkeyhint and autocomplete
Web forms can be made much more usable with a few HTML attributes. Short summary:
The numericality validator does not care about your BigDecimal precision
Looking at the source code of the validates_numericality_of validator, it becomes clear that it converts the attribute in question to either an integer or float:
if configuration[:only_integer]
unless raw_value.to_s =~ /\A[+-]?\d+\Z/
record.errors.add(attr_name, configuration[:message] || ActiveRecord::Errors.default_error_messages[:not_a_number])
next
end
raw_value = raw_value.to_i
else
begin
raw_value = Kernel.Float(raw_val...
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...
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...
Jasmine: Preventing unhandled promise rejections from failing your test
You have an async function that rejects:
async function failingFunction() {
throw new Error("Something went wrong")
}
When you call that function in a test, your test will fail:
it('has a test', function() {
failingFunction() // this will fail your test
})
The failure message will look like this:
Unhandled promise rejection: Error: Something went wrong
You can fix this by expecting the state of the returned promise:
it('has a test', async function() {
await expectAsync(failingFunction()).toBeRej...
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...
Understanding database Indexes in PostgreSQL
I found the linked article very helpful to refresh my understanding of database indexes. As a small bonus, it includes a few helpful SQL oneliners like these two:
Warning
Do not run random code snippets unless you understand them in detail - especially in production.
How Haml 6 changes attribute rendering, and what to do about it
Haml 6 was a major rewrite with performance in mind. To achieve a performance improvement of 1.7x, some design trade-offs had to be made. The most notable change might be the simplified attribute rendering.
In Haml 5, attribute rendering knew two special cases: an attribute with value true
would be rendered without a value, an attribute with a falsy value would not be rendered at all. All other values would just be rendered as attribute values.
According to the Haml maintai...
Simple Form: Rendering errors without an appropriate attribute
Usually you add errors to :base in ActiveRecord, in case no appropriate attribute could be used to add the error.
Simple Form doesn't render errors on :base
by default, but here a few options how you can render these on demand. For all the options below we use the following example with a Simple Form Bootstrap configuration:
- @user = Backend::User.new
- @user.errors.add(:base, 'First error')
- @user.errors.add...
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/...