We no longer use non-deterministic versions like lts/gallium
. This is not supported by all tools. In particular asdf is sunsetting its support for LTS aliases.
tl;dr
Prefer request specs over end-to-end tests (Capybara) to joyfully test file downloads!
Testing file downloads via Capybara is not easy and results in slow and fragile tests. We tried different approaches and the best one is just okay.
Tests for file downloads via Capybara ...
It's 2024 and we have tools like ffmpeg, imagemagick and GPT readily available. With them, it's easy to convert texts, images, audio and video clips into each other.
For the everyday use without any parameter tweaking I'm using a collection of tiny scripts in my ~/bin
folder that can then be used as bash functions. And: It's faster to use the CLI than interacting with a website and cheaper to use the API than buying GPT plus.. :-)
text-to-image "parmiggiano cheese wedding cake, digital art"
If you want to see how long your database queries actually take, you need to disable MySQL's query cache. This can be done globally by logging into a database console, run
SET GLOBAL query_cache_type=OFF;
and restart your rails server.
You can also disable the cache on a per query basis by saying
SELECT SQL_NO_CACHE * FROM ...
You also probably want to disable Rails internal (per-request) cache. For this, wrap your code with a call to ActiveRecord::Base.uncached
. For example, as an around_filter
:
d...
We want to keep a changelog for all gems we maintain. There are some good practices for writing a changelog that adds value, please stick to these.
A changelog is a file which contains a curated, chronologically ordered list of notable changes for each version of a project.
To make it easier for users and...
process
definitions are only applied to the original filebefore
/after
) are applied to original file and each version by itself#version_name
: version uploaders return the version name, whereas the original uploader instance returns nil
If you want to system-wide disable the microphone of your external webcam in PulseAudio use the following one-liners:
# Connected cards
$ pactl list short cards
1 alsa_card.pci-0000_00_1f.3 module-alsa-card.c
5 alsa_card.usb-Lenovo_ThinkPad_Thunderbolt_4_Dock_USB_Audio_000000000000-00 module-alsa-card.c
6 alsa_card.usb-HD_Webcam_C270_HD_Webcam_C270-02 module-alsa-card.c
# Disable HD_Webcam_C27
$ pactl list short cards | grep HD_Webcam_C27 | cut -f2 | xargs -rt -I % pactl set-card-profile % off
pactl s...
console
command: You can now globally disable the IRB multiline feature by setting irb_flags: --no-multiline
in ~/.config/geordi/global.yml. All configured irb_flags are automatically passed on to the console IRB.console
command: Ctrl + C
now properly exits a local Rails consolerspec
and cucumber
commands: Run specs even if the automatic chromedriver update failsdump
command: Drop ...Rachel Andrew has built a website about CSS Grid.
You can chain multiple Capybara matchers on the page
or any element:
expect(page)
.to have_content('Example Course')
.and have_css('.course.active')
.and have_button('Start')
When you chain multiple matchers using and
, [Capybara will retry the entire chain](https://github.com/teamcapybara/capybara/blob/c0cbf4024c1abd48b0c22c2930e7b05af58ab284/lib/capybara/rspec/matc...
A list of implementation details that make for a better / expected user experience. Have these in mind when implementing a web design.
This document outlines a non-exhaustive list of details that make a good (web) interface. It is a living document, periodically updated based on learnings. Some of these may be subjective, but most apply to all websites. The WAI-ARIA spec is deliberately not duplicated in this document. However, some accessibility guidelines may be pointed out.
Non-static elements will not inherit their parent's opacity in IE for no good reason. This can lead to unexpected behaviour when you want to fade/hide an element and all its children.
To fix it, give the parent element defining the opacity a non-static positioning. For example:
.parent {
opacity: 0.2;
position: relative; /* for IE */
}
While the linked article describes this problem for IE9 and below, I have encountered the same issue in IE10 and IE11.
Just go away, Internet Explorer!
The CSS property z-index
is not as global as you might think. Actually, it is scoped to a so-called "stacking context". z-indexes only have meaning within their stacking context, while stacking contexts are treated as a single unit in their parent stacking context. This means indices like 99999
should never actually be needed.
In order to create a stacking context with the least possible side effects, use the isolation
property on an...
Trick: Do not use convert
but mogrify
:
mogrify -resize 50% *
This overwrites the original image file.
In contrast, convert
writes to a different image file. Here is an example if you need this:
cd /path/to/image/directory
for i in `ls -1 *jpg`; do convert -resize 50% $i "thumb_$i"; done
A common cause of non-accessible web pages are elements that were made interactive via JavaScript but cannot be focused or activated with anything but the mouse.
Let's take a look at a common example:
<div filter>
<input filter--query="true" id="query" name="query" type="text">
<label filter--reset="true">Clear Search</label>
</div>
The HTML above is being activated with an Unpoly compiler like this:
up.compiler('[filter]', function(filterForm) {
const resetButton = filter...
These are the top ten accessibility errors as researched by TPGi, a company focusing on accessibility. See the linked article for details on each item, as well as instructions on how to do it correctly.
Generally, I am surprised by these items. I would have expected more complex i...
I recently built a screen with a very high and wide table in the center. This posed some challenges:
What I ended up doing is reusing the horizontal page scrollbar (which is naturally fixed at t...
JavaScript objects can have getter and setter functions that are called when a property is read from or written to.
For example, if you'd like an object that has a virtual person.fullName
attribute that dynamically composes person.firstName
and person.lastName
:
var person = {
firstName: 'Guybrush',
lastName: 'Threepwood',
get fullName() {
return this.firstName + " " + this.lastName;
},
set fullName(name) {
var parts = name.split(" ");
this.firstName = parts[0];
this.lastName = parts[1];
}
};
`...
Custom matchers are a useful RSpec feature which you can use to DRY up repetitive expectations in your specs. Unfortunately the default directory structure generated by rspec-rails
has no obvious place to put custom matchers or other support code.
I recommend storing them like this:
spec/support/database_cleaner.rb
spec/support/devise.rb
spec/support/factory_bot.rb
spec/support/vcr.rb
spec/support/matchers/be_allowed_access.rb
s...
Just feeling like refactoring is not a good reason to do it. Make an educated decision: Is the code change worth the effort? Stay straight on track, don't go astray.
Note: Usually, you'd refactor after finishing your story. At times, it might be necessary to refactor up front. But try to keep refactoring out of your current task.
Things should only be optimized a) when they have settled, i.e. haven't changed for a longer time, and b) when there is a measurable gain from th...
It is good programming practice to Don't Repeat Yourself (or DRY). In Ruby on Rails we keep our code DRY by sharing behavior by using inheritance, modules, traits or partials.
When you reuse behavior you want to reuse tests as well. You are probably already reusing examples in unit tests. Unfortunately it is much harder to reuse code when writing integration tests with Cucumber, where you need t...
When you are using lambdas in RSpec to assert certain changes of a call, you know this syntax:
expect { playlist.destroy }.to change { Playlist.count }.by(-1)
While you can define multiple assertions through multiple specs, you may not want to do so, e.g. for performance or for the sake of mental overhead.
RSpec allows chaining expectations simply by using and
.
expect { playlist.destroy }
.to change { Playlist.count }.by(-1)
.and change { Video.count }.by(0)
...