Fuzzy scoping in Rails with PostgreSQL
When you want to filter records in a model where a string column roughly matches a given term, you can use PostgreSQL’s trigram similarity search.
Writing a fuzzy query in Rails
User.where("similarity(name, ?) > 0.3", "John")
This finds all users where the name is similar to "John" with a similarity score above 0.3.
You can tune the threshold:
- Closer to 1.0 = stricter match
- Closer to 0.0 = looser match
Ordering by best match
User
.where("similarity(name, ?) > 0.3", "John")
.order(Arel.sql("similarity(n...
Sidekiq: How to check the maximum client Redis database size
You can check the maximum client Redis database size in Sidekiq with this command.
Sidekiq.redis { |redis| puts redis.info.fetch('maxmemory_human') }
#=> 512.00M
If you just want the maximum database size for a known Redis database URL you can use the Redis Ruby client or the Redis CLI:
Redis database size via Ruby client
irb(main):002> Redis.new(url: 'redis://localhost:16380/1').info.fetch('maxmemory_human')
=> "512.00M"
Redis database size via CLI
$ redis-c...
Testing Accessibility using Orca
Orca is a Linux screen reader. Since it is part of the GNOME project it should come preinstalled with Ubuntu installations.
Getting started
To turn on the screen reader you can either go to Settings > Accessibility and then activate Screen Reader in the "Seeing" section or you can simply type orca in your terminal. Alternatively you can use the default keyboard shortcut super + alt + s to toggle the screen reader.
Note
It may feel quite strange in the beginning to use a screen reader. It is constantly commenting on everyth...
Rails: Configuring the default sorting behaviour
In Rails, the implicit_order_column (added in Rails 6) is a configuration option that helps you define the default sorting behavior of ActiveRecord queries when no explicit ORDER BY clause is provided. This option allows you to specify a column that Rails will use to automatically sort records in a particular order when no specific ordering is given.
Since the id is typically the primary key and automatically indexed, Rails will default t...
Rails: Keeping structure.sql stable between developers
Why Rails has multiple schema formats
When you run migrations, Rails will write your current database schema into db/schema.rb. This file allows to reset the database schema without running migrations, by running rails db:schema:load.
The schema.rb DSL can serialize most common schema properties like tables, columns or indexes. It cannot serialize more advanced database features, like views, procedures, triggers or custom ditionaries. In these cases you must switch to a SQL based schema format:
# in application.rb
config.a...
A "text-wrap: balance" fallback approach
Here is a workaround for when you want to use text-wrap: balance but must also render nicely for browsers that don't support it (mostly Safari <17.5).
Step 1: Put some <br>s into your HTML
First, place explicit line breaks that should work for most cases.
This depends on your use case and is affected by e.g. container widths or user content.
<div class="my-element">
<p>
Average score
<br>
...
Implementing upload progress and remove button with ActiveStorage DirectUpload
DirectUpload allows you to upload files to your file storage without having to wait for the form to submit. It creates AJAX requests to persist the file within your form and wraps them in a little API. This card will show you how to use it in order to create in-place file uploads with progress and a remove button.
This is basic functionality, you may add additional elements, styles and logic to make this look fancy, but the core functionality is the same. I created a file upload that looks like this:
.proc...
ActiveStorage: How to copy / clone an attachment from one record to another
Given there is a user with an attachable avatar:
class User < ApplicationRecord
has_one_attached :avatar
end
You can copy the avatar from one user to another user with the code below:
user_1 = User.first
user_2 = User.create!(
avatar: {
io: StringIO.new(user_1.avatar.download),
filename: user_1.avatar.blob.filename.to_s,
content_type: user_1.avatar.blob.content_type.to_s,
}
)
Note: For large attachments you might need to use a different approach to avoid memory issues.
Using Low-Level Prompts for High-Accuracy AI Coding
The key to unlocking the full potential of LLMs in coding lies in crafting precise prompts. The main challenge is learning how to structure prompts effectively to guide the model toward accurate results. Further evidence supporting this is the fact that Aider already writes ~70% of its own code (as of 02/2025). However, when starting out, your results may fall short of efficiently generating large portions of your code with the...
Shell script to magically configure display setup
Here is a bash script that I use to auto-configure displays on Ubuntu 24.04 with Xorg.
Background
- Ubuntu always sets the primary display to the 1st (i.e. internal) display whenever I connect to a new Dock/Hub.
- I want my primary display to be the large display.
- My notebook is always placed left of external displays, so the 2nd display will be the center (or only) external display and should be primary.
- I also want all my displays to be placed horizontally, but bottom-aligned (the default would be aligned at their top edges)....
Debug your Postgres SQL query plan
When debugging slow SQL queries, it’s helpful to understand the database engine's query plan. Whenever you execute a declarative SQL query, the database generates a "query plan" that outlines the exact steps the engine will take to execute the query. Most of the time, we don’t need to worry about this plan because SQL engines are highly optimized and can generate efficient execution strategies automatically. However, if a query is slow, inspecting the generated plan can help identify bottlenecks and optimization opportunities.
If you're usi...
Rails: Accessing strong parameters
Rails wraps your parameters into an interface called StrongParameters. In most cases, your form submits your data in a nested structure which goes hand in hand with the strong parameters interface.
Example:
curl -X POST -d "user[name]=bob" https://example.com/users
class UsersController
def create
User.create!(params.expect(user: [:name])) # Or User.create!(params.require(:user).permit(:name))
end
end
This works well most of the time...
Rails 8 introduces `params.expect`
The new params.expect method in Rails 8 improves parameter filtering, addressing issues with malformed input and enhancing security. It provides a cleaner, more explicit way to enforce the structure and types of incoming parameters.
What changed
-
Replaces
requireandpermit: Combines both methods for concise parameter validation. - Explicit Array Handling: Requires double array syntax to define arrays of hashes, improving clarity.
- Enhanced Validation: Ensures expected parameter structure, rejecting malformed input wi...
Rails console tricks
Also see the list of IRB commands.
Switching the context
Changes the "default receiver" of expressions. Can be used to simulate a "debugger situation" where you are "inside" an object. This is especially handy when needing to call private methods – just invoke them, no need to use send.
- Switch to an object:
chws $object - Reset to
main:chws - Show current context:
cwws(usually shown in IRB prompt)
[Technical details](https://technology.doximity.com/articles/the-hidden-gems-of-r...
How to disable logging for ActiveStorage's Disk Service routes
In development, we store files using ActiveStorage's disk service. This means that stored files are served by your Rails application, and every request to a file results in (at least!) one non-trivial log entry which can be annoying. Here is how to disable those log entries.
Example
Here is an example of what loading a single <img> in an example application writes to the Rails log.
Started GET "/rails/active_storage/blobs/redirect/..." for ::1 at ...
Processing by ActiveStorage::Blobs::RedirectController#show as SVG
Parameter...
TestProf II: Factory therapy for your Ruby tests—Martian Chronicles, Evil Martians’ team blog
Some key highlights and points from the linked article TestProf II: Factory therapy for your Ruby tests.
The Problem with Factories in Ruby Tests
- Factories are used to easily generate test data.
- However, they can unintentionally slow down test suites by creating unnecessary or excessive associated data (factory cascades).
Understanding Factory-Induced Slowdowns
- Factories often create additional data (e.g., associated records) th...
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.lockfile - Remove the
node_modulesfolder - Run
npm install - Replace all occurrences of
yarnwithnpmin your project
Notes
- With
npmvendored packages with dependencies create their ownnode_modulesfolder within the vendor path. We...
A different testing approach with Minitest and Fixtures
Slow test suites are a major pain point in projects, often due to RSpec and FactoryBot. Although minitest and fixtures are sometimes viewed as outdated, they can greatly improve test speed.
We adopted a project using minitest and fixtures, and while it required some initial refactoring and establishing good practices, the faster test suite was well worth it! Stick with me to explore how these tools might actually be a good practice.
So, why is this setup faster? Partially, it's because minitest is more lightweight than RSpec, which...
Timeouts for long-running SQL queries
While the main goal always is to prevent long-running queries in the first place, automatic timeouts can serve as a safety net to terminate problematic queries automatically if a set time limit is exceeded. This prevents single queries from taking up all of your database’s resources and reduces the need for manual intervention that might destabilize or even crash the application.
As Rails does not set a timeout on database statements by default, the following query will run for an entire day:
ActiveRecord::Base.connection.execute("S...
Open Terminator from nautilus context menu
On our Ubuntu machines we have nautilus file manager with nautilus-extension-gnome-terminal installed. This adds an entry to the context menu (right click) to start a gnome-terminal in the current directory. As I'm mostly using Terminator terminal, I wanted to have a similar context menu entry to launch Terminator directly. I came across this python script that does exactly that.
- Install python3-nautilus:
sudo apt install python3-nautilus - Create `/usr/share/nautilus-...