How to accept more than 4k query parameters in Rails
I have a form with a dynamic number of fields. Submitting it worked fine until I tried out a very large version of it. The development log was not very helpful:
Invalid or incomplete POST params
As it turned out, the following exception did not reach the log output
Rack::QueryParser::QueryLimitError
Error Message: total number of query parameters (6313) exceeds limit (4096)
If you ever happen to be in the same position, this is how to increase the limit of allowed query parameters:
# config/initializers/rack_query_parser.rb
...
Debugging Rails Active Jobs with the Vanilla Adapters
Short reference on how to quickly debug the vanilla Rails job adapters.
Queue Adapters by Environment
| Environment | Adapter | Jobs Run In | Worker Needed? |
|---|---|---|---|
| development | :async |
Rails server process | No |
| test | :test |
Not executed (stored) | No |
| production | :solid_queue |
Separate worker | Yes (bin/jobs) |
Development (:async)
Jobs run in background threads ([Concurrent Ruby ThreadPoolExecutor](https://ruby-concurrency.github.io/concurrent-ruby/maste...
How to iterate over all ActiveRecord models
Sometimes you have a maintenance script where you want to iterate over all ActiveRecord models. Rails provides this out of the box:
# script/maintenance_task.rb
# Load all models eagerly, otherwise you might only get a subset
Rails.application.eager_load!
ApplicationRecord.descendants.select(&:table_exists?).each do |model|
# ...
end
Caution
If you iterate over individual records, please provide a progress indicator: See [https://makandracards.com/makandra/625369-upload-run-scripts-production](https://makandracards.com/...
Rails: Join model table migration template
When creating a database table for a join model without further importance, you can use Rails' create_join_table:
class CreateSchoolsStudents < ActiveRecord::Migration[7.2]
def change
create_join_table :schools, :students, column_options: { foreign_key: true } do |t|
# t.timestamps # Optional
t.index [:student_id, :school_id], unique: true
end
end
end
This will create a table without an id column and without timestamps. It will have school_id and student_id columns with null: false constraints ...
Working with lists of DOM elements in JavaScript
When you query the browser for DOM elements, there are some footguns you should know about.
Some lists are synchronized with the DOM
Some DOM APIs return live lists that automagically update their contents as the underlying DOM is manipulated.
Example
Let's assume we have two <div> elements:
<div id="one"></div>
<div id="two"></div>
We have multiple ways to retrieve a list of these elements. At first glance, they all look the same:
let liveList = element.getElementsByTagName('div')
let nonLiveList = docum...
Faux-disabled fields in HTML forms
You want to prevent input to a form field, but all the solutions have side effects:
- The
[readonly]attribute is only available for text fields, but not for checkboxes, selects, buttons, etc. - The
[disabled]attribute is available for all kinds of fields, but will no longer include the field value in the submitted form data. -
pointer-events: nonestill allows keyboard input, and does not indicate disabledness visually, or to screen readers.
Ye...
Rails: Adding a unique constraint for a has_one association might be a good default
Most of the time, it's a good default to add a unique index on the foreign key when using Rails’ has_one relationship. This ensures the database enforces the 1:1 constraint and raises an error if your application logic ever violates it.
class User < ApplicationRecord
has_one :session, dependent: :destroy
end
class Session < ApplicationRecord
belongs_to :user
end
create_table :users do |t|
t.timestamps
end
create_table :sessions do |t|
t.references :user, null: false, foreign_key: true, index: { unique: true ...
Sentry Local Logging in Ruby
Enable local logging for Sentry when:
- Debugging Sentry event capture locally
- Testing error handling without polluting production metrics
- Developing background jobs and want to see what Sentry captures
How to enable
To capture and log Sentry events locally during development without sending to the server, add this to config/initializers/sentry.rb inside the Sentry.init block:
if Rails.env.development?
# Use dummy transport to prevent actual transmission to Sentry
config.transport.transport_class = Sentry::DummyTran...
Using a virtual column for trigram indexes in PostgreSQL
Full-text search can reach its limits in terms of flexibility and performance. In such cases, trigram indexes (pg_trgm) offer a lightweight alternative.
You can base the index on a virtual column that combines multiple text attributes. A stored virtual column stores the result of an expression as if it were a real column. It is automatically updated when the source columns change and can be indexed like normal data. This keeps your query logic consistent and avoids repeating string concatenation in every search.
def searc...
Unpoly: Passing Data to Compilers
Quick reference for passing data from Rails to JavaScript via Unpoly compilers.
Haml Attribute Syntax
# Ising hash rockets and string symbols (method calls)
= form.text_field :name, 'date-picker': true
# Curly braces or brackets (elements)
%div.container{ id: 'main', 'data-value': '123' }
Simple Values: data-* Attributes
Use for: Scalar values (IDs, strings, booleans)
%span.user{ 'data-age': '18', 'data-first-name': 'Bob' }
up.compiler('.user', (element, data) => {
console.log(...
Unpoly: Compiler Selector Patterns
Quick guide for frequently used compiler selector patterns of Unpoly.
1. BEM Component Pattern
When: Reusable UI components with multiple child elements
Examples: toggleable.js, collapsible.js, searchable_select.js
up.compiler('.toggleable', (toggleable) => {
const checkbox = toggleable.querySelector('.toggleable--checkbox')
const content = toggleable.querySelector('.toggleable--content')
// ...
})
%td.toggleable.-inverted.-ignore-when-not-empty
.toggleable--content
= form.text_fie...
SQL: Fast threshold counts with LIMIT
Performing COUNT(*) on large tables is slow. Sometimes you don’t need the exact number once results exceed a certain threshold.
For example, you may only need to display 100+ in the UI. Using a plain COUNT(*) would scan all matching rows.
The following query would be pretty slow when counting many rows because it has to scan all rows.
SELECT COUNT(*) FROM movies;
Limiting within a subquery
Use a subquery with LIMIT to cap the scan early. ...
Rails 8: The db:migrate task might not run all migrations in db/migrate/ anymore
In Rails 8 the behavior of the rails db:migrate command has changed for fresh databases (see PR #52830).
- Before Rails 8: The command runs all migrations in the folder
db/migrate/* - After Rails 8: The command loads the schema file (
db/schema.rbordb/structure.sql) if existing and runs all pending migrations in the folderdb/migrate/*afterwards
This speeds up the command. But e.g. migrations with data manipulations are missing.
The only way to run all pending mig...
GoodJob: Ensure you get notified about background exceptions
GoodJob and ActiveJob rescue exceptions internally, preventing exception_notification from triggering. This can cause silent job failures.To get notified, subscribe to ActiveJob events and configure GoodJob's on_thread_error hook. This lets you manually call your exception notifier for every retry, discard, or internal GoodJob error.
# config/initializers/good_job.rb
# Manually notify on job failures, as they are handled internally by ActiveJob/GoodJob.
ActiveSupport::Noti...
Format your JavaScript with prettier
prettier calls itself an opinionated code formatter. I recommend using it for your JavaScript and TypeScript code.
prettier only concerns itself with the formatting of your JavaScript (and also some other file types like json or yaml). When you use it, it has an opinion on every single whitespace and linebreak, as well as a few other things. You renamed a variable and now your line is a bit longer than looks good? prettier will reformat your code.
This might not work for you if you have strong opinions yourself....
Ruby: Avoiding errors when casting user input to Integers
There's a method Integer() defined on Kernel, that typecasts everything into an Integer.
Integer("2") # 2
Integer("foo") # Invalid value for Integer() (ArgumentError)
Integer(nil) # Can't convert nil to Integer (TypeError)
Integer([]) # Can't convert Array into Integer (TypeError)
Integer(Object.new) # Can't convert Object into Integer (TypeError)
Integer(2) # 2
Integer("11", 2) # 3
This is very similar but not identical to to_i:
"2".to_i # 2
"foo".to_i #...
Rails: Redirecting the Logger output temporary aka showing Rails logs in the console
Most of the time, when you are interested in any log output,
- you see the logs directly on your console
- or you tail / grep some logfile in a separate terminal window
In rare cases it's helpful to redirect the Logger output temporary to e.g. STDOUT.
Rails.logger = Logger.new(STDOUT)
ActiveRecord::Base.logger = Logger.new(STDOUT)
User.save!
#=> D, [2025-09-08T11:12:26.683106 #1094157] DEBUG -- : User Load (1.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT $1 [["LIMIT", 1]]
Many frameworks in Rails ...
Improve accessibility with [aria-required] in SimpleForm
SimpleForm comes with an option browser_validations which could be used to give fields that have a presence validation the HTML required attribute. We usually turn it off due to difficulties controlling its behavior and appearance. Instead we only mark required fields with an asterisk (*) next to its label. Blind users probably only discover the validation issue after submitting the form due to the now displayed error messages.
A compromise with better acce...
How to define a table name prefix for all Rails models in a given namespace
ActiveRecord computes table names of model classes, and results are usually just like you'd expect.
Adding a prefix for all classes in a namespace can feel a odd or broken, but does not have to be. It's actually very easy when done right.
Summary (tl;dr)
Here's the short version: Define a table_name_prefix method in the namespace module, and do not define any table_name_prefix in ActiveRecord classes inside of it. If this sounds familiar, we have [a card about using it already](https://makandracards.com/makandra/47198-rails-namespac...
Rails: Handling actions that need to happen after all transactions
In Rails 7.2. the feature ActiveRecord.after_all_transactions_commit was added, for code that may run either inside or outside a transaction (we have a special card for nested transactions in general) and needs to perform work after the state changes have been properly persisted. e.g. sending an email.
Example
def publish_article(article)
article.update(published: true)
ActiveRecord.after_all_transactions_commit do
PublishNotification...
Testing for Performance: How to Ensure Your Web Vitals Stay Green
Frontend performance and user experience are orthogonal to feature development. If care is not taken, adding features usually degrades frontend performance over time.
Many years, frontend user experience has been hard to quantify. However, Google has developed some metrics to capture user experience on the web: the Web Vitals. The Core Web Vitals are about "perceived loading speed" (Largest Contentful Paint), reactivity (Interaction to Next Paint) and visual stability (Content Layout Shift).
I have recent...
Simple gem for CLI UIs
If you want to build a small CLI application, that supports more advanced inputs than gets, I recommend using the cli-ui gem. It's a small dependency-free library that provides basic building blocks, like an interactive prompt:
require "cli/ui"
CLI::UI::StdoutRouter.enable
puts CLI::UI.fmt "a small {{red:demo}}"
# supports h, j, k, l, arrows and even filtering
CLI::UI::Prompt.ask("Choose a plan:", options: ["small", "medium", "large"])
or a simple progress bar for long running scrip...
Adding comments to ambiguous database columns
The DB schema is the most important source of truth for your application and should be very self-explanatory. If determining the true meaning of a DB column requires historical research in your issue tracker or reverse engineering of your source code you might consider adding a comment.
Both PostgreSQL and MySQL support comments in the DB schema:
- For new columns: https://guides.rubyonrails.org/active_record_migrations.html#comments
- Changing the comment for existin...
How to: Self-hosted fonts via NPM packages
We usually ship applications that self-host webfonts to comply with GDPR.
Many popular web fonts are available as NPM packages provided by Fontsource.
We recommend using those instead of downloading and bundling font files yourself. (See below for a list of benefits.)
Usage
- Go to fontsource.org and search for the font you want to add (or a font that suits your application).
- Click the font card to vie...