Enabling YJIT
YJIT is Ruby's default just-in-time compiler. It is considered production-ready since Ruby 3.2 (source).
To activate YJIT you need two steps:
- Your
ruby
binary needs to be compiled with YJIT support. - You need to enable YJIT.
Getting a Ruby with YJIT support
We usually install Ruby with tools like rbenv
or asdf
. This compiles the ruby
binary from the source code. Support for YJIT
will be automatically added during this compilation...
DB enums are ordered
A lesser known fact about PG enums is that they are ordered. This can be really handy when values have an implicit ordering.
Let's imagine a record Issue(criticality: string)
. criticality
should have the following three possible values: critical
, medium
, low
.
Sorting with Issue.all.order(criticality: :desc)
will return the following order:
- The
'medium'
issue - The
'low'
issue - The
'critical'
issue
This happens because the database column backing the criticality attribute is a string and PG will use a [collation](...
Switching the package manager from yarn to npm
We recently migrated a Rails application from yarn
to npm
. We decided to go this step instead of upgrading to > Yarn 2.0 to reduce the number of dependencies in our project.
Migration
- Remove the
yarn.lock
file - Remove the
node_modules
folder - Run
npm install
- Replace all occurrences of
yarn
withnpm
in your project
Notes
- With
npm
vendored packages with dependencies create their ownnode_modules
folder within the vendor path. We...
Running Cucumber deletes my whole app!
If a Cucumber run deletes your application directory, an integration fail between Capybara and Capybara Screenshot may be the cause. Capybara Screenshot defaults to storing screenshots in .
, and tidying up screenshots happens to "tidy up" the application as well. Seen with Capybara 2.18 and Capybara Screenshot 1.0.4.
Upgrading Capybara Screenshot to 1.0.26 fixes the issue. Consider also setting Capybara.save_path = 'tmp/capybara'
in an initializer.
Learn how to use ruby/debug
This talk shows simple and advanced usages of the ruby/debug debugger. It goes through a step by step debugging workflow.
Here are some command examples:
(rdbg) step 2 # step twice
(rdbg) info # show current scope, including self
(rdbg) bt # show backtrace
(rdbg) frame 3 # go directly to frame 3
(rdbg) break User#email # add a breakpoint in the email instance method
(rdbg) catch SomeException # break when SomeException is raised
Some advanced exam...
How to allow testing beforeunload confirmation dialogs with modern ChromeDrivers
Starting with ChromeDriver 127, if your application displays a beforeunload
confirmation dialog, ChromeDriver will immediately close it. In consequence, any automated tests which try to interact with unload prompts will fail.
This is because ChromeDriver now follows the W3C WebDriver spec which states that any unload prompts should be closed automatically.
However, this applies only to "HTTP" test sessions, i.e. what you're using by default. The spec also defines that bi-directional test se...
High-level data types with "composed_of"
I recently stumbled upon the Rails feature composed_of. One of our applications dealt with a lot of addresses and they were implemented as 7 separate columns in the DB and Rails models. This seemed like a perfect use case to try out this feature.
TLDR
The feature is still a VERY leaky abstraction. I ran into a lot of ugly edge cases.
It also doesn't solve the question of UI. We like to use
simple_form
. It's currently not possible to simply write `f...
How to query GraphQL APIs with Ruby
While most Rails Apps are tied to at least one external REST API, machine-to-machine communication via GraphQL is less commonly seen. In this card, I'd like to give a quick intro on how to query a given GraphQL API - without adding any additional library to your existing app.
Core aspects of GraphQL
Interacting with GraphQL feels a bit like querying a local database. You are submitting queries to fetch data in a given structure (like SELECT in SQL) or mutations to alter the database (similar to POST/PUT/DELETE in REST). You can ...
Ruby: Retrieving and processing files via Selenium and JavaScript
This card shows an uncommon way to retrieve a file using selenium where JavaScript is used to return a binary data array to Ruby code.
The following code example retrieves a PDF but the approach also works for other file types.
require "selenium-webdriver"
selenium_driver = Selenium::WebDriver.for :chrome
selenium_driver.navigate.to('https://example.com')
link_to_pdf = 'https://blobs.example.com/random-pdf'
binary_data_array = selenium_driver.execute_script(<<-JS, link_to_pdf)
const response = await fetch(arguments[0])
if (!r...
Chrome: disable "Choose your search engine" popup in tests
Fresh Chrome installations now show a "Choose your search engine" popup in Europe. This might make your Cucumber tests fail.
Fortunately there is a flag to disable the popup. Add the following option to your chromedriver setup code:
options.add_argument('--disable-search-engine-choice-screen')
I found this flag in Peter Beverloo's list.
Background: This was experienced locally with google-chrome 127.0.6533.72
. In CI I did not get the popup.
Ruby: Different ways of assigning multiple attributes
This card is a short summary on different ways of assigning multiple attributes to an instance of a class.
Using positional parameters
Using parameters is the default when assigning attributes. It works good for a small number of attributes, but becomes more difficult to read when using multiple attributes.
Example:
class User
def initialize(salutation, first_name, last_name, street_and_number, zip_code, city, phone_number, email, newsletter)
@salutation = salutation
@first_name = first_name
@last_name = last_nam...
Capistrano: Configure environment specific array attributes
Using Capistrano, we usually have some array configurations in the config/deploy.rb
file, like set :linked_files, %w[config/database.yml]
, so in this case we don't have to manage the database configuration individually on every server.
In a specific case, one of our projects supports sign in by SAML
, but not every deploy target has this feature activated. Here comes a nice handy Capistrano feature, which lets us modify the default configuration for individual env...
The Framework Field Guide - Fundamentals | Unicorn Utterances
I used two lab days to read the The framework field guide - Fundamentals, the first of a three part series to learn the basics of frontend technologies. I can highly suggest it for learning the fundamentals. 'The framework field guide' is written by Unicron Utterances and there side has many high quality articles on web development and computer science related to programming.
[The Framework Field Guide](https://unicorn-ut...
Caveat when using Rails' new "strict locals" feature
In Rails 7.1 it has become possible to annotate partials with the locals they expect:
# partial _user_name.erb
<%# locals: (user:) %>
<%= user.name %>
# view
<%= render 'user_name' %> <%# this raises an ArgumentError %>
Unfortunately, when some other code in that template raises an ArgumentError
(for example an error in the User#name
method) you will end up with a confusing stacktrace that looks like you have an error in your render
call.
If th...
routing-filter is broken with Rails 7.1
If you are using the routing-filter gem in your Rails 7.1 app for managing URL segments for locales or suffixes, you will notice that the filters do no longer apply, routes are broken and the necessary parameters are no longer extracted. That is because routing-filter patches Rails' find_routes
-method to get the current path and apply its defined filters on it. These filters then modify the params that are handed over to your controller action. This way you receive a locale
parameter from a ...
Rails: Comparison of assignable_values and Active Record enum types
We are using assignable_values for managing enum values in Rails. Nevertheless Rails is adding more support for enum attributes, allowing to have a closer look at the current feature set in comparison to our still preferred option assignable_values
.
Active Record enum attribute interface
By default Rails is mapping enum attributes to integers:
...
Migrating from Elasticsearch to Opensearch: Overview
Why do we migrate?
Due to a change in licensing, we cannot provide Elasticsearch versions >= 8.0.
Version 7.17.x will reach EOL status with the release of Elasticsearch version 9.
We have decided to use OpenSearch as a replacement, since it is a fork of Elasticsearch version 7.10.2, still running under the previous licensing model and wire-compatible.
A more detailed reasoning can be found on their [website](https://opensearch.o...
Caution: rem in @media query definitions ignore your font-size
Note
Using rem only ever makes sense when the root font size is dynamic, i.e. you leave control to the user. Either by a) respecting their user agent defaults, or by b) offering multiple root font sizes in your application.
By defining @media queries in rem, they will accommodate to the root font size of your page. At a larger root font, breakpoints will be at larger widths, scaling with the font. However, there is a catch in case b) mentioned in the note above.
Relative length units in media queries are based on the initial value,...
Problems with git submodules in Gitlab CI
If you are using git submodules in Gitlab CI, you might run into a "The project you were looking for could not be found or you don't have permission to view it."
Gitlab added a feature that new projects are no longer allowed to be cloned inside CI runs of other repositories by default. To fix this
- Go into the project used as a submodule
- Go to "Settings" -> "CI/CD" (if you don't see this section, enable it in "Settings" -> "General" -> "Visibility, project features, permissions")
- Go to "Token Access"
- Either disable "Limit access to ...
Rails: Testing file downloads with request specs
tl;dr
Prefer request specs over end-to-end tests (Capybara) to joyfully test file downloads!
Why?
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 ...
- ... are slow,
- ... are fragile (breaks CI, breaks if Selenium driver changes, ...),
- ... need workarounds for your specia...
Geordi 10.0.0 released
10.0.0 2024-03-07
Compatible changes
-
console
command: You can now globally disable the IRB multiline feature by settingirb_flags: --nomultiline
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 console -
rspec
andcucumber
commands: Run specs even if the automatic chromedriver update fails - Improve detection of IRB version
- Add new hints to 'Did you know'
Breaking changes
-
dump
command: Drop...
Grid by Example: a website about CSS Grid
Rachel Andrew has built a website about CSS Grid.
- Video tutorials
- More than 30 layout examples for feature demonstration
- Layout patterns for copy-paste use
- All grouped by topic: "Placing items onto the grid", "Sizing of tracks and items" etc. with video, linked articles, examples each
Chaining Capybara matchers in RSpec
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...
Virtual scrolling: A solution for scrolling wide content on desktops
I recently built a screen with a very high and wide table in the center. This posed some challenges:
- Giving the table a horizontal scroll bar is very unergonomic, since the scrollbar might be far off screen.
- Making the whole page scrollable looks bad, since I don't want the rest of the UI to scroll.
- Giving the table its own vertical scrollbar and a limited height would have solved it, but felt weird, since the table was 90% of the page.
What I ended up doing is reusing the horizontal page scrollbar (which is naturally fixed at t...